这是我参与8月更文挑战的第十四天,活动详情查看:8月更文挑战
绑定规则
我们来看看在函数的执行过程中调用位置如何决定this的绑定对象。我们需要先找到调用位置,然后判断需要应用四条规则中的哪一条。首先让我们来看看这四条规则
默认绑定
首先要介绍的是最常用的函数调用类型:独立函数调用。可以把这条规则看成兜底的默认规则。
function foo(){
console.log(this.a);
}
var a = 2;
foo(); //打印2
声明在全局作用域中的变量就是全局对象的一个同名属性。(比如上面的a = 2)当我们调用foo()时,this.a被解析成了全局变量a。为什么会这样呢?因为函数调用时,应用了this的默认绑定,因此this是指向全局对象的。
隐式绑定
另一条需要考虑的规则是调用位置是否有上下文对象,或者说是否被某个对象拥有或者包含。
function foo(){
console.log(this.a);
}
var obj = {
a:1,
foo:foo
};
obj.foo(); //打印2
当foo()被调用时,它的前面加上了对obj的引用。当函数引用有上下文对象时,隐式绑定规则会把函数调用中的this绑定到这个上下文对象。因为调用foo()时this被绑定到obj,因此this.a和obj.a是一样的。注意:对象属性引用链中只有最后一层在调用位置中起作用。
隐式丢失
一个非常常见的this绑定问题就是被隐式绑定的函数会丢失绑定对象,也就是说它会应用默认绑定的规则。
function foo(){
console.log(this.a);
}
var obj = {
a:2,
foo:foo
};
var bar = obj.foo;
var a = 3;
bar(); //打印3
虽然bar是obj.foo的一个引用,但是实际上,它引用的是foo函数本身,因此此时的bar()实际上是一个不带任何修饰的函数调用,因此应用了默认绑定。 一种更常见并且出人意料的情况发生在传入回调函数时:
function foo(){
console.log(this.a);
}
function doFoo(fn){
fn(); //fn()的调用位置;
}
var obj = {
a:2,
foo:foo
};
var a = 3; //全局变量3
doFoo(obj.foo); //打印3
参数传递实际上是一种隐式赋值,因此我们传入函数时也会被隐式赋值,所以结果和上一个例子一样。回调函数丢失this绑定是非常常见的。除此之外,还有一种情况this的行为会出乎我们意料:调用回调函数的函数可能会强制的修改this。