绑定规则
this的绑定规则总结起来总共有四种:
- 默认绑定
- 隐式绑定
- 显式绑定
- new绑定
默认绑定
这条规则是无法应用其它绑定时的默认规则,思考以下代码:
| |
foo()是直接使用不加任何修饰的函数引用进行调用的,因此只能应用默认绑定,在非严格模式下this默认绑定到了全局对象
严格模式下则被绑定到undefined
| |
隐式绑定
另一条需要考虑的规则是调用位置是否有上下文对象,或者说是否被某个对象拥有或者包含,
思考下面代码:
| |
调用位置obj.foo()会使用obj上下文来引用函数,因此可以说函数被调用时obj对象"拥有"或者"包含"它,当函数引用有
上下文对象时,隐式绑定会把函数调用中的this绑定到这个上下文对象。
对象引用链只有最后一层在调用位置起作用, 举例来说
| |
隐式丢失问题
一个常见的问题就是被隐式绑定的函数会丢失绑定对象。
例子:
| |
虽然bar引用的是obj.foo,但是bar实际上引用的是foo函数本身,因此,此时的bar()是一个不带
任何修饰的函数调用,所以foo应用了默认绑定。
显式绑定
JavaScript中所有的函数都具有的方法call和apply
通过bar.call(obj)可以强制将foo的this绑定到obj上
如果call和apply被传入了一个原始值(字符串类型,布尔类型或者数字类型)来当做this的绑定对象,这个原始值会被转换成
对象的形式(也就是 new String(…)…),这通常称作"装箱"
硬绑定
硬绑定的典型应用场景就是创建一个包裹函数,负责接收函数参数并返回值
| |
或者构建一个简单的绑定辅助函数
| |
ES5中内置的bind方法
bind()会返回一个硬绑定的函数,无论在哪里调用(除了使用new),这个this以及传入的arguments都会生效
API调用上下文
许多函数提供了绑定this的参数,比如forEach(callback, thisArg)
| |
new绑定
思考下面代码:
| |
使用new来调用foo时,构造的新对象会被绑定到foo(...)调用中的this上
优先级
new绑定 > 显式绑定 > 隐式绑定 > 默认绑定
绑定例外
被忽略的this
如果把null, undefined,作为this的绑定对象传入call``apply或者bind,这些值在调用时会被
忽略,实际应用的是默认绑定规则。
间接引用
经典的例子:
| |
赋值表达式p.foo = o.foo返回的是目标函数的引用,因此调用位置是foo(),这里会应用默认绑定。
箭头函数
箭头函数不使用this的四种标准规则,而是根据外层的作用域来决定this,箭头函数的绑定无法修改,new 也不行。