Function.prototype.bind()总是很慢吗?

时间:2013-09-19 12:59:33

标签: javascript performance v8 spidermonkey late-binding

我正在编写一个开源的javascript库,并且我大量使用.bind()方法,因为我知道面向对象的代码看起来更清晰。 (有争议,但

示例

A1:

var that = this;

setTimeout(function () {
    that.method();
}, 0);

VS

B1:

setTimeout(this.method.bind(this), 0);

或者,更实用的代码部分

A2:

remoteDataSource.getData(function (a, b, c, d) {
     obj.dataGetter(a, b, c, d);
})

vs B2:

remoteDataSource.getData(obj/* or prototype */.dataGetter.bind(obj));

我为旧浏览器使用非原生bind,在我打开jsperf benchmark for bind之前,一切都很完美。

使用bind的代码看起来慢了100倍。现在,在重写我的所有库之前,我对那些熟悉javascript引擎的人有一个问题:

作为新功能,bind是否有可能得到优化  很快,还是因为JavaScript架构限制而没有机会?

2 个答案:

答案 0 :(得分:14)

首先,修复了jsperf http://jsperf.com/bind-vs-emulate/13

=您不应在基准测试中重新创建静态函数。这是不现实的,因为在实际代码中,静态函数只创建一次。

您可以看到var self = this模式仍然快了大约60%。但它需要内联函数定义,因为您可以从任何地方进行绑定,因此具有更好的可维护性。


嗯,不,内置的绑定语义是荒谬的错综复杂。

当我绑定时,我只想要这个:

function bind(fn, ctx) {
    return function bound() {
        return fn.apply(ctx, arguments);
    };
}

如果我想预先应用参数或使用一些深层构造黑魔法,我会想要一个完全不同的功能。我不知道为什么任何这个都包含在bind中。

< rant>顺便说一下,同样的问题出现在ES5中引入的几乎所有内容中,通过强制实现处理一些与实际中任何人都不相关的理论边缘情况来惩罚常见情况。下一个语言版本继续在同一条路径上。< / rant>

模拟绑定甚至根本不会尝试模拟绑定。即使你试图模仿它,你也无法做到 完全做到这一点,这是不公平的。

所以在其他条件相同的情况下*内置绑定不能比只是绑定的常识自定义绑定更快。

*在JIT中,用户代码对内置代码没有明显的缺点。事实上,SM和V8都实现了许多内置插件 在Javascript。

答案 1 :(得分:0)

目前,2013年末,最佳解决方案是实施Function.prototype.bind手工版本,并使用您自己的javascript代码覆盖供应商的“原生”(不是真正的原生)方法,或使用您自己的myBind

Function.prototype.apply相当快,并且数组切片,连接和移位速度很慢,因此如果apply更好地使用bind,或者最小化myBind函数中的参数操作。这将使您没有预填充参数的功能。

所以我认为没有必要将所有内容重写回闭包(丑陋的var that = this;)。让javascript的功能性获胜。

此处提供更多详细信息和工作代码示例:

http://jsperf.com/function-bind-performance/4

http://jsperf.com/function-bind-performance/5

http://jsperf.com/bind-vs-emulate/4 .. 10。

总结:找到的解决方法并不是那么糟糕。勇敢地使用它们。如果你没有使用功能不全的bind,请不要偏离原始概念,因为我没有发现它尚未在C中实现的原因。这是一个时间问题。