gpt4 book ai didi

javascript - 为什么绑定(bind)比闭包慢?

转载 作者:IT老高 更新时间:2023-10-28 21:49:27 25 4
gpt4 key购买 nike

以前的发帖人问 Function.bind vs Closure in Javascript : how to choose?

并部分收到了这个答案,这似乎表明绑定(bind)应该比闭包更快:

Scope traversal means, when you are reaching to grab a value (variable,object) that exists in a different scope, therefore additional overhead is added (code becomes slower to execute).

Using bind, you 're calling a function with an existing scope, so that scope traversal does not take place.

两个 jsperfs 表明 bind 实际上比 closure 慢得多。 .

这是作为对上述内容的评论发布的

而且,我决定写 my own jsperf

那么为什么绑定(bind)这么慢(70+% 在 Chrome 上)?

既然它不是更快,而且闭包可以达到同样的目的,应该避免绑定(bind)吗?

最佳答案

Chrome 59 更新:正如我在下面的答案中预测的那样,使用新的优化编译器绑定(bind)不再慢。这是带有详细信息的代码:https://codereview.chromium.org/2916063002/

大多数时候都没有关系。

除非您正在创建一个应用程序,其中 .bind 是我不会打扰的瓶颈。在大多数情况下,可读性比纯粹的性能更重要。我认为使用原生 .bind 通常会提供更易读和可维护的代码——这是一个很大的优势。

但是,是的,当它重要时 - .bind 更慢

是的,.bind 比闭包要慢得多 - 至少在 Chrome 中,至少在 v8 中的当前实现方式。由于性能问题,我个人不得不切换到 Node.JS(更一般地说,在性能密集型情况下,闭包有点慢)。

为什么?因为 .bind 算法比用另一个函数包装一个函数并使用 .call.apply 复杂得多。 (有趣的是,它还返回一个 toString 设置为 [native function] 的函数)。

有两种方式来看待这个问题,从规范的 Angular 来看,从实现的 Angular 来看。让我们观察两者。

首先,让我们 look at the bind algorithm defined in the specification :

  1. Let Target be the this value.
  2. If IsCallable(Target) is false, throw a TypeError exception.
  3. Let A be a new (possibly empty) internal list of all of the argument values provided after thisArg (arg1, arg2 etc), in order.

...

(21. Call the [[DefineOwnProperty]] internal method of F with arguments "arguments", PropertyDescriptor {[[Get]]: thrower, [[Set]]: thrower, [[Enumerable]]: false, [[Configurable]]: false}, and false.

(22. Return F.

看起来很复杂,不仅仅是一个包装。

第二,我们看how it's implemented in Chrome .

我们来看看FunctionBind在 v8(chrome JavaScript 引擎)源代码中:

function FunctionBind(this_arg) { // Length is 1.
if (!IS_SPEC_FUNCTION(this)) {
throw new $TypeError('Bind must be called on a function');
}
var boundFunction = function () {
// Poison .arguments and .caller, but is otherwise not detectable.
"use strict";
// This function must not use any object literals (Object, Array, RegExp),
// since the literals-array is being used to store the bound data.
if (%_IsConstructCall()) {
return %NewObjectFromBound(boundFunction);
}
var bindings = %BoundFunctionGetBindings(boundFunction);

var argc = %_ArgumentsLength();
if (argc == 0) {
return %Apply(bindings[0], bindings[1], bindings, 2, bindings.length - 2);
}
if (bindings.length === 2) {
return %Apply(bindings[0], bindings[1], arguments, 0, argc);
}
var bound_argc = bindings.length - 2;
var argv = new InternalArray(bound_argc + argc);
for (var i = 0; i < bound_argc; i++) {
argv[i] = bindings[i + 2];
}
for (var j = 0; j < argc; j++) {
argv[i++] = %_Arguments(j);
}
return %Apply(bindings[0], bindings[1], argv, 0, bound_argc + argc);
};

%FunctionRemovePrototype(boundFunction);
var new_length = 0;
if (%_ClassOf(this) == "Function") {
// Function or FunctionProxy.
var old_length = this.length;
// FunctionProxies might provide a non-UInt32 value. If so, ignore it.
if ((typeof old_length === "number") &&
((old_length >>> 0) === old_length)) {
var argc = %_ArgumentsLength();
if (argc > 0) argc--; // Don't count the thisArg as parameter.
new_length = old_length - argc;
if (new_length < 0) new_length = 0;
}
}
// This runtime function finds any remaining arguments on the stack,
// so we don't pass the arguments object.
var result = %FunctionBindArguments(boundFunction, this,
this_arg, new_length);

// We already have caller and arguments properties on functions,
// which are non-configurable. It therefore makes no sence to
// try to redefine these as defined by the spec. The spec says
// that bind should make these throw a TypeError if get or set
// is called and make them non-enumerable and non-configurable.
// To be consistent with our normal functions we leave this as it is.
// TODO(lrn): Do set these to be thrower.
return result;

我们可以在实现中看到一堆昂贵的东西。即%_IsConstructCall()。这当然需要遵守规范 - 但在许多情况下它也比简单的包装慢。


另一方面,调用 .bind 也略有不同,规范注释“使用 Function.prototype.bind 创建的函数对象没有原型(prototype)属性或 [[Code]],[ [FormalParameters]] 和 [[Scope]] 内部属性"

关于javascript - 为什么绑定(bind)比闭包慢?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17638305/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com