JavaScript中理解关于this关键字的所有信息

Posted by cl9000 on March 27, 2020

不畏惧失败是创造力的一个基本要素。——<艾尔文·兰德博士>

作者:Ashish Lahoti
译者:cl9000
来源:https://codingnconcepts.com/javascript/this-keyword-in-javascript/

JavaScript 中的 this 关键字是一个非常重要的概念,但同时也非常容易混淆。

JavaScript 中,this 关键字指的是它所属的对象。它有不同的值取决于它被使用的地方:

  • 在方法中,this 引用定义方法的所有者对象
  • 单独使用,this 引用全局对象
  • 在函数中,this 指向全局对象
  • 在严格模式的函数中,thisundefined
  • 当一个函数使用 new 关键字调用时,this引用新的对象实例
  • 在DOM事件中,this 指的是接收事件的元素。
  • 函数原型方法call()apply()bind()可用于 将this 指向任何对象。

this 在方法中

当执行对象的方法时,this将引用定义了方法的对象。

在下面的示例中,this引用person对象,因为fullName()方法是在person对象中定义的。

1
2
3
4
5
6
7
8
9
var person = {
firstName: "John",
lastName : "Doe",
fullName : function() {
return this.firstName + " " + this.lastName;
}
};

console.log(person.fullName()); // John Doe

下面再看一个例子obj1obj2在执行它们自己的increment()方法,这里this分别指obj1obj2

1
2
3
4
5
6
7
8
9
var increment = function(){
return console.log(this.a + 1);
}

var obj1 = { a: 1, increment: increment };
var obj2 = { a: 2, increment: increment };

obj1.increment(); //this = obj1
obj2.increment(); //this = obj2

Output
2
3

this 单独使用

当你单独使用this时,它引用全局对象

我们看一下单独使用时this的值:

1
console.log(this); //this = window

Output
Window {parent: Window, opener: null, top: Window, length: 4, frames: Window, …}

我们看到this是指Window对象,它是浏览器的全局对象。

记住: 在严格模式下,单独使用时,this也引用全局对象。

this 在函数中(默认)

对于一个函数(位于顶层或不在任何函数内部),this引用全局对象。

1
2
3
4
5
function topLevelFunction(){
console.log(this);
}

topLevelFunction(); //this = window

在上面的例子中,this指的是浏览器的全局对象window

this 在函数中(严格)

然而,对于处于严格模式的函数(位于顶层或不在任何函数内部),this指的是undefined

请看下面的例子,在严格模式函数中this指的是undefined:

1
2
3
4
5
6
'use strict';
function topLevelFunction(){
console.log(this);
}

topLevelFunction(); //this = undefined

再举一个例子,如果在严格模式下调用increment()函数,this引用undefined并抛出错误。

1
2
3
4
5
6
7
var a = 1;
var increment = function(){
'use strict';
return console.log(this.a + 1);
}

increment(); //this = undefined

Output
Uncaught TypeError: Cannot read property ‘a’ of undefined

this with new

当使用new关键字调用函数时,该函数被称为构造函数并返回一个新对象。在本例中,this指的是一个新创建的对象。

1
2
3
4
5
6
7
8
9
10
11
12
13
var Person = function(firstName, lastName){
this.firstName = firstName;
this.lastName = lastName;
this.getFullName = function(){
console.log(`${this.firstName} ${this.lastName}`);
}
}

let person1 = new Person("Albert", "Einstein");
let person2 = new Person("Isaac", "Newton");

person1.getFullName(); //this = person1
person2.getFullName(); //this = person2

Output
Albert Einstein
Isaac Newton

this with 显示绑定

函数有call()apply()bind()原型方法,可以在函数上调用它们来显式地改变this上下文。

我们逐一查看这些方法,并看看它们之间的区别

call()

1
ƒ.call(this, arg1, arg2, ...)

当使用call()方法调用函数时,

  • 第一个参数由this引用
  • 后面的逗号分隔的参数是方法参数

记住: call()参数用逗号分隔。

apply()

1
ƒ.apply(this, [arg1, arg2, ...])

当使用apply()方法调用函数时,

  • 第一个参数由this引用
  • 第二个参数是一个值数组,都是方法参数

记住: apply()接受数组形式的参数

bind()

1
ƒ.bind(this)

使用bind()方法调用函数时

传递给bind()函数的参数由this引用
返回新的绑定函数,其上下文被this传递参数

记住: bind()方法不调用函数。它返回一个可以稍后调用的新函数。

我们看一个例子,如何使用这三个函数原型方法call(), apply()和bind()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
let numObj1 = {num: 1};
let numObj2 = {num: 2};

let sumFn = function(...args){
console.log(this.num + args.reduce((a,b)=> a+b, 0));
}

sumFn.call(numObj1, 1, 2, 3, 4); //this = numObj1
sumFn.call(numObj2, 1, 2, 3, 4); //this = numObj2

sumFn.apply(numObj1, [1,2,3,4]); //this = numObj1
sumFn.apply(numObj2, [1,2,3,4]); //this = numObj2

let sumBindFn1 = sumFn.bind(numObj1); // return Fn
let sumBindFn2 = sumFn.bind(numObj2); // return Fn
sumBindFn1(1, 2, 3, 4); //this = numObj1
sumBindFn2(1, 2, 3, 4); //this = numObj2

output:
11
12
11
12
11
12

参考

关注【公众号】,了解更多。
关注【公众号】,了解更多。
关注【公众号】,了解更多。



支付宝打赏 微信打赏

赞赏一下 坚持原创技术分享,您的支持将鼓励我继续创作!