这是我参与8月更文挑战的第二十天,活动详情查看:8月更文挑战
优先级
之前已经介绍了函数调用中this绑定的四条规则,我们需要做的就是找到函数的调用位置并判断应该应用哪条规则。如果有多条规则呢?此时规则的优先级就起作用了。默认绑定的优先级是四条中最低的,所以可以先不考虑。
判断this
我们可以根据优先级来判断函数在某个调用位置应用的是哪条规则。可以按照下面的顺序来进行判断:
- 函数是否在new中调用(new绑定)?如果是的话this绑定的是新创建的对象。
- 函数是否通过call、apply(显式绑定)或者硬绑定调用?如果是的话,this绑定的是指定的对象。
- 函数是否在某个上下文对象中调用(隐式绑定)?如果是的话,this绑定的是那个上下文对象。
- 如果都不是的话,使用默认绑定。(严格模式下绑定undefined,非严格模式绑定全局对象)
绑定例外
在某些场景下的this绑定行为会出乎意料。当你认为应该用其他绑定规则时,实际上用了默认的绑定规则。
被忽略的this
比如使用apply()来“展开”一个数组,并当做参数传入一个函数。类似的,bind()可以对函数进行柯里化,这种方法有时候挺有用的:
function (a,b){
console.log('a:' + a + ',b:' + b);
}
foo.apply(null,[2,3]); //a:2,b:3
var bar = foo.bind(null,2);
bar(3); //a:2,b:3
这两种方法都需要传入一个参数当this的绑定对象。如果函数不关心this的话,仍然需要传入一个占位值,这种时候传null看上去没什么问题。然而,总是用null来忽略this的绑定可能会产生副作用。如果某个函数确实用了this,那默认绑定规则会把this绑定到全局对象。(PS:上面的例子在ES6之后可以用展开运算符...来替代apply)
所以我们可以传入一个特殊的对象,把this绑定到这个对象不会对程序产生任何的副作用。
function foo(a,b){
console.log('a:' + a + ',b:' + b);
}
var Ø = Object.create(null);
foo.apply(Ø,[2,3]); //a:2,b:3
var bar = foo.bind(Ø,2);
bar(3); //a:2,b:3