题目 23 / 31
链式调用末尾的 .call() 绑定的是外层调用还是内层调用?
知识点: this 绑定难度: 高级
call 只会附着在它直接调用的那个具体函数值上,且只在那一次调用生效。
使用执行可视化器解题在下方逐步观察每个绑定、函数调用和控制台输出。预测输出结果
预测三组共六行输出。每一行都先调用 foo,再立即调用 foo 返回的函数——请对每一行分别推演。
var obj = {
a: 'obj',
foo: function () {
console.log('foo:', this.a);
return function () {
console.log('inner:', this.a);
};
}
};
var a = 'window';
var obj2 = { a: 'obj2' };
obj.foo()();
obj.foo.call(obj2)();
obj.foo().call(obj2);查看答案与完整解析
正确输出
foo: obj
inner: window
foo: obj2
inner: window
foo: obj
inner: obj2为什么会这样
obj.foo()() 先以 obj.foo() 的形式调用 foo——隐式绑定,因此 foo: obj。这次调用返回一个普通的内部函数,随后它被裸调用,没有接收者,于是 inner: window(默认绑定)。
obj.foo.call(obj2)() 在第一次调用时就显式把 foo 自己的 this 绑定为 obj2,所以 foo: obj2。但返回的内部函数依然是作为一次独立的、无接收者的调用被执行的,所以还是 inner: window——前面的 .call(obj2) 对它没有任何影响。
obj.foo().call(obj2) 先以隐式绑定调用 foo(foo: obj,不受后面任何操作影响),然后才把 .call(obj2) 链接到返回的内部函数上,只对这一次具体的调用强制 inner: obj2。
这道题考察什么
- call/apply/bind 只对它们被调用的那个具体函数值的这一次调用生效
- 返回的闭包是一个独立的函数值,拥有自己单独决定的 this
- 从左到右阅读调用链,就能准确看出每个 .call() 附着在哪次调用上
运行环境前提
假设运行在经典的非严格模式脚本中;返回的内部函数是普通函数,裸调用时依然遵循默认绑定。