前言
JavaScript 中的 this 表现与其他语言略有不同。本文介绍了 this 在不同情况下的指向,包括全局作用域,默认绑定,隐式绑定,显式绑定,构造函数,箭头函数。
this
与其他语言相比,函数的 this 关键字在 JavaScript 中的表现略有不同,此外,在严格模式和非严格模式之间也会有一些差别。在绝大多数情况下,函数的调用方式决定了 this 的值(运行时绑定)。this 不能在执行期间被赋值,并且在每次函数被调用时 this 的值也可能会不同。
常见的this指向:
- 全局作用域中或普通函数中的
this指向全局对象window,严格模式下普通函数中的this为undefined。 - 立即执行函数的
this指向window。 - 定时器的
this指向window,因为setTimeout()是window上的方法。 - 事件中的
this指向事件源对象。 - 方法中的
this指向调用方法的对象。 - 构造函数中
this指向新建的对象实例。
this 的绑定
默认绑定
普通函数调用模式,又或者称为默认绑定,当一个函数不是一个对象的属性,直接作为函数来调用时,this指向全局对象,而在严格模式下 this 为 undefined。
console.log(this === window); // true
隐式绑定
方法调用模式,又或者称为隐式绑定,如果一个函数作为一个对象的方法来调用时, this 指向这个对象。
下面代码中 foo() 的第一个 this 是 obj,test() 里的 this 是 window ,因为test() 是独立调用的,调用的是 test() 而非 obj.test()。
obj无法直接调用test(),这里的obj.test()是为了更好的理解隐式绑定中函数要作为对象的方法被调用。或者
this指向最后调用它的那个对象,这样比较好理解。
bar 拿到了 obj.foo 的引用,然后在全局下独立调用,打印的 this 均为 window。
let obj = {
foo: function () {
console.log(this); // obj
function test() {
console.log(this); // window
}
test();
}
};
obj.foo();
let bar = obj.foo;
bar(); // window
显式绑定
我们通过 call()、apply() 和bind() 调用模式,又或者称为显式绑定,可以使用这三个方法显示地指定调用函数的 this 指向。
构造函数
构造器调用模式,如果一个函数用 new 调用时,函数执行前会新创建一个对象,this 指向这个新创建的对象。
new调用时的返回值,如果没有显式返回对象或者函数,才是返回生成的新对象,不能简单的用typeof判断对象。
优先级
这四种方式的优先级:new 调用(构造器调用模式)> 显式绑定(call()、apply() 和bind() 调用模式)> 隐式绑定(方法调用模式)> 默认绑定(普通函数调用模式)。
箭头函数
ES6中提出了箭头函数,它的语法比函数表达式更简洁,并且没有自己的 this、arguments、super 或 new.target。箭头函数表达式更适用于那些本来需要匿名函数的地方,并且它不能用作构造函数。
箭头函数中的 this:
- 箭头函数没有自己的
this,只能捕获其所在上下文的this值作为自己的this。箭头函数的this绑定的是最近一层非箭头函数的this,否则为全局对象。 - 箭头函数继承来的
this指向不会改变,这有利于封装回调函数。 call、apply、bind等方法不能改变箭头函数this的指向。- 箭头函数不能作为构造函数使用,因为没有自己的
this,也就无法通过new操作符使this指向生成的新对象。
下面使用 Babel 将箭头函数转成 ES5 代码,就能清楚地说明this的指向。箭头函数里面根本没有自己的 this,而是引用了外层的 this。
// ES6
function foo() {
setTimeout(() => {
console.log('id:', this.id);
}, 100);
}
// ES5
function foo() {
var _this = this;
setTimeout(function () {
console.log('id:', _this.id);
}, 100);
}
参考资料
this - JavaScript | MDN
箭头函数 - JavaScript | MDN
函数的扩展 - ECMAScript 6入门
前端面试题之JavaScript篇
面试官问:JS的this指向 - 掘金
this、apply、call、bind - 掘金
this指向/箭头函数this指向详解 - 掘金