从绑定This的四种方式来全面解析JS中的This。
资料来源于You Don’t Know JS系列丛书
感谢作者的开源以及YDKJS的中文翻译
默认绑定(Default Binding)
第一种This绑定规则可以认为是没有其他规则适用时的默认规则。考虑下面这个代码段:
- 独立函数的调用,无其他规则适用,所以This被绑定到全局对象。
- 要注意的是默认绑定在strict模式下是不合法的。此时的This将会返回undefined
- 如果函数内容没有在严格模式中运行,即使他在严格模式的上下文中被调用,this依旧能返回全局对象。(当然,应该尽量避免使用严格和非严格模式混合)
隐含绑定(Implicit Binding)
当函数调用点有一个环境对象(context object),也称为拥有者(owning)或容器(containing)对象
则他将被隐含绑定到该对象。考虑下面这段代码:
当他是被这样调用时:obj1.obj2.foo();
只有obj2时影响调用点的。
隐含绑定的丢失
当一个隐含绑定丢失,则他将会退回默认绑定。
尽管bar似乎是obj.foo的引用,但实际上他知识foo的一个引用。这样就很好理解了:bar()就等同于foo()。显然符合默认绑定
考虑回调函数:
与上面一样,fn知识foo的一个引用。
而下面的明确绑定将解决隐含绑定的丢失。
明确绑定(Explicit Binding)
很简单,就是通过call,apply,bind方法将this绑定到某一个环境上下文中
其中call、apply类似,他们将会立刻调用函数,而bind不会。
new绑定(new Binding)
考虑下面的代码:
通过在前面使用new来调用foo(..),我们构建了一个新的对象并这个新对象作为foo(..)调用的this。 new是函数调用可以绑定this的最后一种方式,我们称之为 new绑定(new binding)。
四种绑定的顺序
bind绑定高于new,明确绑定高于隐含绑定高于默认绑定
判定this
- 函数是和new一起被调用的吗(new绑定)?如果是,this就是新构建的对象。
var bar = new foo() - 函数是用call或apply被调用(明确绑定),甚至是隐藏在bind 硬绑定 之中吗?如果是,this就是明确指定的对象。
var bar = foo.call( obj2 ) - 函数是用环境对象(也称为拥有者或容器对象)被调用的吗(隐含绑定)?如果是,this就是那个环境对象。
var bar = obj1.foo() - 否则,使用默认的this(默认绑定)。如果在strict mode下,就是undefined,否则是global对象。
var bar = foo()