this三要素
- this的值只有在执行时才能确定。
- this的值需要根据执行上下文来判断。
- 在严格模式下,有时this的值会与非严格模式有所不同。
1. 在全局上下文中
在全局上下文中,也就是在任何函数的外部,this指向全局对象。
此时,严格模式和非严格模式下,this的取值是一样的。
在浏览器环境中,this指向浏览器的全局对象,即window。
在node server环境中,this指向node的全局对象,即global。
console.log(this === window); //true
2. 在函数上下文中
2.1. 简单函数
在非严格模式下,this的取值是window。
function foo() {
return this;
}
console.log(foo() === window); //true
在严格模式下,this的取值是undefined。
function foo() {
'use strict';
return this;
}
console.log(foo() === window); //false
console.log(foo()); //undefined
2.2. 箭头函数
箭头函数中的this,需要通过查找作用域链来决定。如果箭头函数被非箭头函数所包含,则this绑定的是最近的一层非箭头函数的this;否则,如果箭头函数没有被任何非箭头函数所包含,那么它的this是全局对象。
const foo = (() => this);
foo();
在上面的代码中,箭头函数的外围函数是foo,foo的this是全局变量window,所以箭头函数的this也是window。
const foo = function(){
'use strict';
return (() => this);
};
foo()(); // undefined
将上面的代码修改成严格模式,箭头函数的外围函数还是foo,但由于foo被设定为严格模式,foo的this是undefined,所以箭头函数的this也是undefined。
2.3. 函数作为对象的属性
函数作为对象的属性,this指向该对象。
function foo() {
return this;
}
foo();
const obj = {a: foo};
obj.a(); // obj
2.4. 构造函数
当通过new关键字调用构造函数时,JavaScript内部处理的过程实际上执行的是函数的内部方法[[construct]],这个方法负责创建一个实例,然后再执行函数体,将this绑定到实例上。
当然,也可以不通过new关键字来调用构造函数,这时JavaScript内部处理的过程实际上执行的是内部方法[[call]],从而直接执行代码中的函数体。
function Person(name) {
this.name = name;
}
const person = new Person('zhangsan');
const notPerson = Person('lisi');
console.log(person.name); //zhangsan
console.log(notPerson.name); //undefined
console.log(window.name); //lisi
3. 调用了bind方法的函数
bind方法可以指定一个函数的this,并且使this的值永远不变。
const obj = {a: 1};
const foo = function(){
return this;
}.bind(obj);
const foo2 = function(){
return this;
};
const obj2 = {
f: foo,
f2: foo2
};
obj2.f(); //obj
obj2.f2(); //obj2
从上面的代码可以看到:函数f2作为对象obj2的属性,其this指向了对象obj2;函数f同样作为对象obj2的属性,但它使用了bind方法被永久绑定到了对象obj上了,所以它的this永远指向obj。
4. call、apply
call和apply提供了指定this的值的方法。
function foo(a, b) {
return this.n + a + b;
}
var n = 10;
foo(1, 2); // this === window, this.n = 10
const obj = {n: 1};
foo.call(obj, 1, 2); //this === obj, this.n = 1
foo.apply(obj, [1, 2]); //this === obj, this.n = 1
结语
分析JavaScript的this指针,需要根据执行上下文和严格模式/非严格模式来综合的分析,本文列出了一些基本场景,可以帮助理解this指针在不同场景下的取值。