关于EcmaScript-5 Function.prototype.bind实现,我有一个非常有趣的问题。通常在使用bind时,可以这样做:
var myFunction = function() {
alert(this);
}.bind(123);
// will alert 123
myFunction();
好的,这很酷,但是当我们这样做时会发生什么?
// rebind binded function
myFunction = myFunction.bind('foobar');
// will alert... 123!
myFunction();
我理解,就Function.prototype.bind的实现方式(https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/bind)而言,这是完全合乎逻辑的行为。但在现实生活中,这种行为完全没用,不是吗?问题是:是bug还是功能?如果它是一个错误,为什么它没有提到?如果它是一个功能,为什么那么具有原生“绑定”实现的谷歌浏览器的行为完全相同?
为了更清楚,我认为更有意义的是,这里是以不同的方式实现Function.prototype.bind的代码片段:
if (!Function.prototype.bind) {
Function.prototype.bind = function() {
var funcObj = this;
var original = funcObj;
var extraArgs = Array.prototype.slice.call(arguments);
var thisObj = extraArgs.shift();
var func = function() {
var thatObj = thisObj;
return original.apply(thatObj, extraArgs.concat(
Array.prototype.slice.call(
arguments, extraArgs.length
)
));
};
func.bind = function() {
var args = Array.prototype.slice.call(arguments);
return Function.prototype.bind.apply(funcObj, args);
}
return func;
};
}
所以现在试试这个:
// rebind binded function
myFunction = myFunction.bind('foobar');
// will alert... "foobar"
myFunction();
在我看来,取代“this”更有意义......
那你们怎么想呢?
答案 0 :(得分:14)
Function.prototype.bind
的先例是在各种JS框架中实现该想法。据我所知,他们都没有允许this
- 绑定被后续绑定更改。你也可以问为什么他们都没有允许这种绑定改变,以问为什么ES5不允许它。
你不是我听过的唯一一个认为这个奇怪的人。使用Mozilla的JS引擎的Chris Leary(就像我一样)认为这有点奇怪,几个月前在Twitter上提出了这个问题。在一个稍微不同的形式中,我记得有一个Mozilla实验室的黑客质疑是否有某种方法可以“解除绑定”一个函数,从中提取目标函数。 (如果你可以这样做,你当然可以将它绑定到另一个this
,至少如果你也可以提取绑定的参数列表也传递它。)
我不记得在指定bind
时正在讨论的问题。但是,当这个东西被淘汰时,我并没有特别关注es-discuss邮件列表。也就是说,我不相信ES5想在这个领域进行创新,只是“铺一条牛路”,借用一句话。
如果您撰写了足够详细的提案,您可能可能会提出一些内省的方法来解决这些问题以进行讨论。另一方面,绑定是一种信息隐藏机制,会削弱其采用。如果你有时间,可能值得尝试提出一些建议。我的猜测是隐藏信息会妨碍提案被采纳。但这只是一个可能错误的猜测。只有一种方法可以找到...
答案 1 :(得分:2)
当你绑定一个函数时,你要求一个新的函数忽略它自己的这个伪参数,并用一个固定的值调用原始函数。
另一次绑定此函数具有完全相同的行为。如果bind会以某种方式在新的中修补它,那么对于已经绑定的函数,它将具有特殊情况。
换句话说,bind在“正常”函数上的工作原理与bind返回的函数完全相同,并且在没有重要因素的情况下,保持函数的语义复杂度较低是一种很好的工程 - 它更容易记住绑定对函数的作用,如果它以完全相同的方式处理所有输入函数,而不是专门处理某些输入函数。
我认为您的混淆是您将bind视为修改现有函数,因此,如果再次修改它,则需要再次修改原始函数。但是,bind不会修改任何内容,它会创建具有特定行为的新函数。新功能本身就是一个功能,它不是原始功能的魔法补丁版本。
因此,没有任何关于为什么它被标准化或以它的方式发明的东西:bind返回一个提供new this和prepends参数的函数,并且对所有函数都一样。最简单的语义。
只有这种方式才真正安全使用 - 如果bind会在已经绑定的函数和“普通”函数之间产生差异,那么必须在绑定之前进行测试。一个很好的例子是jQuery.each,它传递了一个新的。如果bind将特殊绑定函数,则没有安全的方法将绑定函数传递给jQuery.each,因为这将在每次调用时被覆盖。要解决这个问题,jQuery.each必须以某种方式特殊地绑定绑定函数。