解引用变量的闭包有用吗?

IT技术 javascript closures dereference
2021-01-16 12:23:18

我不确定取消引用变量是否或何时有用(以提高性能)。

var x = a.b.c.d[some_key].f;
while (loop) {
    do_something_with(x);
}

似乎比

while (loop) {
    do_somthing_with(a.b.c.d[some_key].f);
}

这是需要的还是由智能 JavaScript 引擎自动完成的?

但我的实际问题是我是否应该这样做,例如,在图书馆。

(function() {
    var slice = Array.prototype.slice;

    Function.prototype.x = function x() {
        var args = slice.call(arguments, 0);
        ...
    };
})();

要不就

Function.prototype.x = function x() {
    var args = Array.prototype.slice.call(arguments, 0);
    ...
};

引擎无法自动改进这一点,因为它不知道Array.prototype.slice在运行时是否会发生变化。

那么:创建一个用于创建 slice 函数的局部引用的闭包会使脚本更快吗?或者额外的闭包范围是否使它比访问 Array 的属性“原型”的属性“切片”更慢?

3个回答

为此,“取消引用”实际上是一个令人困惑的词。不是这样,你只是在局部变量中缓存一些属性/方法。实际上,无论是访问随机对象上的某些属性/方法还是使用Array.prototype.slice. 这使得很多的感觉,只要你访问这些深层嵌套的属性不止一次

Tbh,“现代”浏览器确实优化了很多访问。所有现代 js 引擎都使用内部查找表来访问属性。但是,您仍然希望缓存那些深度嵌套的内容,因为在较旧的引擎中,它会贯穿所有涉及的对象来解决它。

使用本地缓存引用的另一个原因是,即使使用了某种显式或隐式eval机制,即使是现代 js 引擎也不会立即使用哈希查找

尤其是 Internet Explorer <9 和 Firefox 3.5,随着进入(原型)链的每一个额外步骤,都会导致可怕的性能损失。


提醒一句:不是很推荐对对象方法使用本地缓存(就像您对slice方法所做的那样)。许多对象用于this确定它们被调用的上下文。将方法存储在局部变量中会导致this绑定到global objectnull所以总是确保调用这样的方法method.call来手动设置上下文。

@Bergi:那个测试用例不是很有用。正如我所提到的,如果您只打算访问嵌套的属性/方法一次,那么访问它当然更快。该测试用例调用函数,获取引用,然后访问引用。必须更慢,不需要进行基准测试。
2021-03-29 12:23:18
正如 Jared Farish 所建议的,我已经在jsperf.com/prop-acess-vs-closures设置了一个测试用例Firefox 和 Opera 在跨链时似乎都更快。但是:在我添加第三个测试用例之前,链和闭包方法完全相等。
2021-04-08 12:23:18

如果您打算多次访问一个属性,请考虑将其分配给一个局部变量。然而,对于现代 javascript 引擎,这种微优化几乎没有什么区别,最重要的是编写表达您意图的代码。

对于这个特定问题,您无论如何都希望有一个实用程序函数:

function toArray( arrayLike ) {
    return Array.prototype.slice.call( arrayLike );
}

...或者如果您关心性能:

var toArray = (function () {
    var slice = Array.prototype.slice;

    return function ( arrayLike ) {
        return slice.call( arrayLike );
    };
})();

你不想slice.call在你的代码到处都是这种结构......