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

Is a closure for dereferencing variables useful?

本文关键字:有用 闭包 引用 变量      更新时间:2023-09-26

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

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的属性"prototype"的属性"slice"慢吗?

"解引用"实际上是一个令人困惑的词。不是这样的,你只是在一个局部变量中缓存一些属性/方法。它实际上没有区别,无论你这样做是为了访问一个随机对象上的一些属性/方法,还是用Array.prototype.slice。一旦你不止一次地访问那些嵌套的属性, 就会使更有意义。

老实说,"现代"浏览器确实对访问进行了大量优化。所有现代js引擎都使用内部查找表来访问属性。然而,你仍然想要缓存那些深度嵌套的东西,因为在旧的引擎中,它将沿着所有涉及的对象的整个路径来解决它。

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

尤其是Internet Explorer <9和Firefox 3.5,每增加一步(原型)链就会导致严重的性能损失。


需要注意的是:不建议对对象方法使用本地缓存(就像使用slice方法那样)。许多对象使用this来确定它们被调用的上下文。将方法存储在局部变量中会导致this绑定到global objectnull。所以一定要确保使用method.call调用这样的方法来手动设置上下文。

如果您打算多次访问一个属性,请考虑将其赋值给局部变量。然而,对于现代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结构…