【发布时间】:2017-10-02 14:55:19
【问题描述】:
这是一个纯粹的理论问题。
我正在从“你不知道 js”中学习 javascript,并且我被困在 JS 中 bind 函数的实现上。考虑以下代码:
function foo(something) {
this.a = something;
}
var obj1 = {};
var bar = foo.bind(obj1);
bar(2);
console.log(obj1.a); // 2
var baz = new bar(3);
console.log(obj1.a); // 2
console.log(baz.a); // 3
在上面的sn-p中,我们将foo()绑定到obj1,所以foo()中的this属于obj1,这就是为什么当我们调用obj1.a时obj1.a变成2bar(2) .但是new 运算符可以优先,并且obj1.a 不会改变,即使bar(3) 与new 一起调用也是如此。
下面是MDN页面为bind(..)提供的polyfill:
if (!Function.prototype.bind) {
Function.prototype.bind = function(oThis) {
if (typeof this !== "function") {
// closest thing possible to the ECMAScript 5
// internal IsCallable function
throw new TypeError( "Function.prototype.bind - what " +
"is trying to be bound is not callable"
);
}
var aArgs = Array.prototype.slice.call( arguments, 1 ),
fToBind = this,
fNOP = function(){},
fBound = function(){
return fToBind.apply(
(
this instanceof fNOP &&
oThis ? this : oThis
),
aArgs.concat( Array.prototype.slice.call( arguments ) )
);
}
;
fNOP.prototype = this.prototype;
fBound.prototype = new fNOP();
return fBound;
};
}
根据本书允许新覆盖的部分是:
this instanceof fNOP &&
oThis ? this : oThis
// ... and:
fNOP.prototype = this.prototype;
fBound.prototype = new fNOP();
所以,现在是重点。根据书: “我们实际上不会深入解释这个诡计是如何工作的(它很复杂,超出了我们的范围),但本质上,该实用程序确定是否使用 new 调用了硬绑定函数(导致新构造的对象是它的this),如果是这样,它使用新创建的 this 而不是之前为 this 指定的硬绑定。”
bind() 函数中的逻辑如何允许new 运算符覆盖硬绑定?
【问题讨论】:
-
您可能会发现this answer 很有用。
-
语言具有定义和实现的编译时和运行时语义。在解析和编译 JS 程序时,会找到带有
new运算符的调用。已知此运算符用于调用函数以构造新对象。因此,遵循规范为这种情况定义的特定算法。与任何呼叫一样,其中一部分是将this设置为正确的值。没有真正的魔法。语言实现只是遵循规则。 -
另外,请记住,polyfill 是纯粹用 JS 编写的“尽力而为”的实现。他们无法访问语言实现的内部结构,因此有时无法完美地代表规范的要求。
-
这是一个简单的例子
function Foo(x) { console.log(this instanceof Foo); }->Foo(4)= falsenew Foo(4)= true。 -
@Utkanos 这真的很有帮助,但仍然没有解释
new如何能够优先于硬绑定