javascript this 關鍵字

javascript this 關鍵字

javascript this 關鍵字

寫在前面

创建时间:2020-09-17 22:12:48

主要分析js中this關鍵字在不同環境中的區別

也包括function 與 ()=>中的

版本:

  • node 12.9.1
  • chrome 74.0.3729.157 (正式版本) (64 位元) JavaScript V8 7.4.288.28
  • firfox 80.0.1 (64-bit)

參考資料

  1. https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/this
  2. https://www.runoob.com/js/js-this.html
  3. https://www.cnblogs.com/Nancy-wang/p/6928395.html
  4. https://www.php.cn/java/base/435044.html
  5. https://www.cnblogs.com/twoheads/p/9876396.html

正篇

何爲this

this是面向對象編程中可以看作是對當前對象的應用,指向當前對象本身,例如在java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
/**
* @description: Admin對象
* @author: Hermit_Yoshino
* @create: 2020-04-07 15:32
**/
public class Admin {
private String adminAccount;
private String password; //成員變量

public Admin(String adminAccount, String password) {
// adminAccount 局部變量
this.adminAccount = adminAccount;
this.password = password;
}

public String getAdminAccount() {
return adminAccount;
}

public void setAdminAccount(String adminAccount) {
this.adminAccount = adminAccount;
}

public String getPassword() {
return password;
}

public void setPassword(String password) {
this.password = password;
}

@Override
public String toString() {
return "Admin{" +
"adminAccount='" + adminAccount + '\'' +
'}';
}
}

使用this關鍵字我們區分局部變量與成員變量

但是在js中this卻和java等一些面相對象變成語言有些不同

js中的this

1
2
3
4
5
6
7
8
9
10
11
// 以下是在chrome中測試的結果
var test = function(){this.name = "name"}
// undefined //輸出
this.name
// "" //輸出
test()
// undefined //輸出
this.name
// "name" //輸出
this
// Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, parent: Window, …} //輸出
1
2
3
4
5
6
7
8
9
10
11
// 以下是在firfox中測試的結果
var test = function(){this.name = "name"}
// undefined //輸出
this.name
// "" //輸出
test()
// undefined //輸出
this.name
// "name" //輸出
this
// Window about:home //輸出
1
2
3
4
5
6
7
8
var test = function(){this.name = "name"}
console.log(this.name)
test()
console.log(this.name)
console.log(this)
// undefined
// undefined
// Object {}
1
2
3
4
5
6
7
8
9
10
11
//套娃測試 chrome
var test = function(){this.name = "name"; var a = function(){this.name = "Akeno" }; a()}
// undefined
this.name
// ""
test()
// undefined
this.name
// "Akeno"
this
// Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, parent: Window, …}

通過測試我們可以看到在瀏覽器中,this關鍵詞指的就是Window,當然你也無法重新定義this(至少我試了不行),無論你在哪裏使用this都一樣都是一樣的記過

但在node中卻不是那樣,再用一個更具體的來測試一下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47

var test_fun = function(){
this.value = 100;
return value
}
console.log(test_fun())
console.log(value)
console.log(this.value)

const test_obj = {
value: 10,
func: function() {
value = 1
var a = function (){
this.value = 2
}
a()
return value;
},
};

console.log(test_obj.func());
// 100
// 100
// undefined
// 2

const test_obj = { // 來個套娃
value: 10,
func: function() {
value = 1
var a = function (){
this.value = 2
}
a()
return this.value;
},
};

console.log(test_obj.func());
// 10

var f1 = function(){
return this
}
console.log(globalThis === f1())
// true

注:js嚴格模式與非嚴格模式會有區別,我這裏是非嚴格模式

從上面的測試結果可以看出,在function中的this指的是函數所屬者,直接使用的話者的就是全局對象

1
2
console.log( __dirname );
// 打印當前文件的路徑

如果當作對象來處理呢

1
2
3
4
5
6
var name = function () {
this.name = "Akeno";
}
var obj = new name();
console.log(obj.name);
// Akeno

Html中的Dom元素結果有如何呢

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
</head>
<body>
<button id="test">
click me
</button>
</body>
<script>
document.querySelector("#test").addEventListener("click", function(){
console.log(this)
})
</script>
</html>

chrome

firfox

在js的class中代碼為嚴格模式,所以this為undefined

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Animal { 
speak() {
return this;
}
static eat() {
return this;
}
}

let obj = new Animal();
obj.speak(); // Animal {}
let speak = obj.speak;
speak(); // undefined

Animal.eat() // class Animal
let eat = Animal.eat;
eat(); // undefined

簡單總結

引用網上大神的總結

  1. 单独使用 this,它指向全局(Global)对象。瀏覽器中就是window
  2. 函数使用中,this 指向函数的所属者。
  3. 在对象方法中, this 指向调用它所在方法的对象。
  4. 严格模式下函数是没有绑定到 this 上,这时候 this 是 undefined。
  5. 在 HTML 事件句柄中,this 指向了接收事件的 HTML 元素。
  6. apply 和 call 允许切换函数执行的上下文环境(context),即 this 绑定的对象,可以将 this 引用到任何对象。(這個之後研究)

關於this在function與箭頭函數中

1
2
3
4
5
6
7
8
9
10
11
var f1 = () => {
return this
}
var f2 = function(){
return this
}

console.log(f1())
console.log(f1() === this)
console.log(f2())
console.log(f2() === globalThis)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
this.birth = 2030
let birth = 2010
var obj = {
birth: 1990,
getAge: function () {
birth = 2000
var fn = function(){
birth = 2010
return new Date().getFullYear() - this.birth;
}
return fn();
}
};
console.log(isNaN(obj.getAge()))
// true
// 這裏爲什麽是NAN我是沒想明白
1
2
3
4
5
6
7
8
9
10
11
12
13
var obj = {
birth: 1990,
getAge: function () {
birth = 2000
var fn = function(){
birth = 2010
return 2020 - this.birth
}
return fn();
}
};
console.log(obj.getAge())
// 10
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var obj = {
birth: 1900,
getAge: function () {
birth = 1910
var fn = function(){
birth = 1920
var fu1 = function(){
birth = 1930
return 2020 - this.birth
}
return fu1()
}
return fn();
}
};
console.log(obj.getAge())
// 90
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
var obj = {
birth: 1900,
getAge: function (callback) {
birth = 1910
var fn = function(callback){
birth = 1920
var fu1 = function(callback){
birth = 1930
return callback()
}
return fu1(callback)
}
return fn(callback)
}
};
console.log(obj.getAge(function(){
birth = 1940
return 2020 - this.birth
}))
// 80
//可能是我時間太多了
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
this.birth = 1800
var obj = {
birth: 1900,
getAge: function() {
birth = 1910
var fn = function() {
birth = 1920
var fu1 = () => {
birth = 1930
var fu2 = () => {
birth = 1940
return 2020 - this.birth
}
return fu2()
}
return fu1()
}
return fn();
}
};
console.log(obj.getAge())
// 80
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
this.birth = 1800
var obj = {
birth: 1900,
getAge: () => {
birth = 1910
var fn = () => {
birth = 1920
var fu1 = () => {
birth = 1930
var fu2 = () => {
birth = 1940
return 2020 - this.birth
}
return fu2()
}
return fu1()
}
return fn();
}
};
console.log(obj.getAge())
// 220
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
this.birth = 1800
var obj = {
birth: 1900,
getAge: function(){
birth = 1910
var fn = () => {
birth = 1920
var fu1 = () => {
birth = 1930
var fu2 = () => {
birth = 1940
return 2020 - this.birth
}
return fu2()
}
return fu1()
}
return fn();
}
};
console.log(obj.getAge())
// 120

通過測試我們可以發現,箭頭函數修正了function中this指向混亂的問題