盒子
盒子

JavaScript 中 this 是如何工作的?

废话

经历了一个非常紧急的迭代,加班加到怀疑人生,收拾心情,重新捡起blog,争取做一个更博小能手。

之前印象

JS中this的工作原理,是自古以来的必考点。有一句经典的话,谁最终调用函数,this指向谁。这句话听起来好像很简单,但是结合各种场景,this分别是如何指向的呢?

##具体场景

全局作用域

1
2
3
4
5
6
// global scope
foo = 'abc';
alert(foo); // abc

this.foo = 'def';
alert(foo); // def

在全局作用域/全局环境(global scope/global context)中,this指向的就是全局变量
在浏览器中指的就是window,在node.js中就是global。

函数中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var boat = {
size: 'normal',
boatInfo: function() {
alert(this === boat);
alert(this.size);
}
};

boat.boatInfo(); // true, 'normal'

var bigBoat = {
size: 'big'
};

bigBoat.boatInfo = boat.boatInfo;
bigBoat.boatInfo(); // false, 'big'

从上述代码中可以看,同样是boatInfo()打印出来确实不同的值,这是因为在任何函数中,this的指向都不是静态的(static),它总是在你调用一个函数,但尚未执行函数内部代码前被指定,是由调用函数的父作用域提供的,这就是那句经典的话的来源。
接着上面在深一级

1
2
var boatInfo = bigBoat.boatInfo;
boatInfo();//false,undefined

这就是因为执行boatInfo函数的父作用域是全局,所以this指向了全局。

构造函数中

当使用new关键字去执行构造函数时,构造函数中的this指向的的就是新建的那个对象实例。

1
2
3
4
5
6
var thisArg;
function Ctor(){
thisArg = this
}
var instance = new Ctor()
console.log(thisArg === instance) //true

箭头函数

当使用es6箭头函数时,默认绑定外层第一个不是箭头函数的this,并且this一旦绑定,就不会被call,apply,bind改变。

1
2
3
4
5
6
var obj = {
foo:()=>{
console.log(this)
}
}
obj.foo()//window|global

总结

this的指向判断可以遵循一个方法,在非箭头函数下,通过()左边的对象,如果是一个引用,那么this就指向该对象,如果没有,就指向全局,如果有箭头函数存在,就绑定了外层第一个不是箭头函数的this。