Function.prototype.bind

Function.prototype.bind

本文关键字:bind prototype Function      更新时间:2023-09-26

我有一个关于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还是特性?如果是bug,为什么没人提?如果这是一个功能,为什么谷歌Chrome与本地"绑定"实现完全相同的方式?

为了更清楚,在我看来更有意义,下面是实现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"更有意义…

你们怎么看?

Function.prototype.bind的先例是在各种JS框架中实现这个想法。据我所知,它们都不允许this绑定被后续绑定所改变。你可能会问为什么它们都不允许更改绑定,就像问为什么ES5不允许一样。

你不是唯一一个觉得这很奇怪的人。从事Mozilla JS引擎开发的Chris Leary(和我一样)认为这有点奇怪,几个月前他在Twitter上提出了这个问题。以一种不同的形式,我记得Mozilla实验室的一个黑客质疑是否有某种方法可以"解绑定"一个函数,从中提取目标函数。(如果你能做到这一点,你当然可以将它绑定到一个不同的this,至少如果你也可以提取绑定的参数列表来传递它。)

我不记得在指定bind时讨论过这个问题。然而,当这些东西被讨论出来的时候,我并没有特别关注es- discussion邮件列表。也就是说,我不认为ES5在这个领域有太多的创新,借用一句短语,只是"铺路"。

如果你写了一份足够详细的提案,你也许可以提出一些内省的方法来解决这些问题。另一方面,绑定是一种信息隐藏机制,这不利于它的采用。如果你有时间的话,不妨试着提点建议。我的猜测是信息隐藏的顾虑会阻碍提案被采纳。但这只是一个猜测,很可能是错误的。

当你绑定一个函数时,你要求一个新的函数忽略它自己的this伪参数,并使用this的固定值调用原始函数。

下次绑定该函数具有完全相同的行为。如果bind要以某种方式在其中添加一个新的this,则必须对已经绑定的函数进行特殊处理。

换句话说,bind对"普通"函数的作用与对bind返回的函数的作用完全相同,并且在没有覆盖因素的情况下,保持函数的语义复杂性是很好的工程——如果以完全相同的方式处理所有输入函数,而不是特殊处理某些输入函数,则更容易记住bind对函数的作用。

我认为你的困惑是,你认为绑定是修改一个现有的函数,因此,如果你再次修改它,你期望原始函数再次被修改。然而,bind并不修改任何东西,它创建了一个具有特定行为的新函数。新函数本身就是一个函数,它不是对原函数的一个神奇的补丁版本。

因此,它被标准化或被发明的原因并不神秘:bind返回一个提供新的this和前置参数的函数,并且在所有函数上都是一样的。最简单的语义。 只有这样使用才是安全的——如果绑定会使已经绑定的函数和"正常"的函数产生差异,那么必须在绑定之前进行测试。jQuery就是一个很好的例子。每个,它传递一个新的this。如果bind会对绑定函数进行特殊处理,那么将绑定函数传递给jQuery就没有安全的方法了。每个,因为这将在每次调用时被覆盖。为了解决这个问题,使用jQuery。每个函数都必须对绑定函数进行特殊处理。