调用位置
调用位置就是函数在代码中被调用的位置,而找到调用位置之前,我们还要知道调用栈(就是为了达到当前执行位置所调用的所有函数)。我们关心的调用位置就在当前正在执行的函数的前一个调用中。
|
|
绑定规则
找到调用位置,然后判断需要应用下面四条规则中的哪一条。
默认绑定
独立函数调用,不带任何修饰的函数引用进行调用。
如果使用严格模式,则不能将全局对象用作默认绑定,因此this会指向 undefined。
隐式绑定
当函数引用有上下文时,隐式绑定规则会把函数调用中的this绑定到这个上下文对象。对象属性引用链中只有上一层在调用位置起作用。
隐式丢失
隐式使用时会遇到 隐式丢失
隐式丢失还会发生在传入回调函数的时候
所以一定要小心别名陷阱,类似于 setTimeout(obj.foo, 10) ,里面的obj.foo参数也是一个别名陷阱,会导致隐式丢失
显示绑定
使用javascript的 call(…)和apply(…) 方法,直接指定this的绑定对象,因此我们称之为显示绑定。
|
|
硬绑定
显示绑定无法解决丢失绑定问题,但是他的变种硬绑定可以。
|
|
硬绑定的bar不可能再修改他的this,强制把foo的this绑定给了obj,因此无论之后怎么调用bar,他总会手动的在obj上调用foo。
还可以把他创建成一个可重复使用的辅助函数:
注*: ES5内置了bind方法,foo.bind(obj)
new绑定
首先我们要知道使用new来调用函数(发生构造函数调用)的时候,会执行哪些操作:
- 创建一个全新的对象
- 这个新对象会被执行[[Prototype]]连接
- 这个新对象会绑定到函数调用的this
- 如果函数没有返回其他对象,那么new表达式中的函数调用会自动返回这个新对象
在new的时候,会在内存的某处创建一个新的对象,然后这个新对象的prototype连接到他的constructor,同时也会把他constructor上面的方法、this绑定给自己。
|
|
优先级
- 显示绑定 > 隐式绑定
- new绑定 > 隐式绑定
- new其实是创建了一个新的对象
- 默认绑定优先级最低
判断this
- 函数是否在new中调用(new绑定)?如果是的话this绑定的是新创建的对象
- 函数是否通过call, apply(显示绑定)或者硬绑定调用?如果是的话,this绑定的是指定的对象
- 函数是否在某个上下文对象中调用(隐式绑定)?如果是的话,this绑定的是那个上下文对象
- 如果都说不是的话,使用默认绑定。如果在严格模式下,this就绑定到undefined,否则绑定到全局对象
小结
如果要判断一个运行函数的this绑定,首先找到这个函数的调用位置,然后通过四条规则来判断this的绑定对象。
- 由new调用?绑定到新创建的对象
- 由call或者apply(或者bind)?绑定到指定的对象
- 由上下文调用?绑定到上下文对象
- 默认: 在严格模式下绑定到undefined,否则绑定到全局对象