关于javascript:解除引用变量的闭包是否有用?

Is a closure for dereferencing variables useful?

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

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

似乎比

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

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

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

1
2
3
4
5
6
7
8
(function() {
    var slice = Array.prototype.slice;

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

或者只是

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

发动机不能自动改善这一点,因为它不知道Array.prototype.slice是否会在运行期间发生变化。

那么:创建一个闭包来创建对slice函数的本地引用会使脚本更快吗?或者附加的闭包范围是否使其比访问数组的属性"原型"的属性"切片"慢?


"取消引用"实际上是一个混淆的词。不是这样,您只需要在局部变量中缓存一些属性/方法。实际上,无论是访问随机对象上的某个属性/方法,还是使用Array.prototype.slice进行访问,都没有什么区别。一旦您多次访问这些嵌套很深的属性,这就非常有意义。

tbh,"现代"浏览器确实对访问进行了大量优化。所有现代JS引擎都使用内部查找表来访问属性。但是,您仍然希望缓存那些嵌套很深的东西,因为在旧的引擎中,它将通过所有涉及的对象来解决问题。

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

尤其是InternetExplorer<9和FireFox3.5每增加一步(原型)链,都会导致严重的性能损失。

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


如果要多次访问属性,请考虑将其分配给局部变量。然而,对于现代的JavaScript引擎来说,这样的微优化几乎没有什么不同,最重要的是编写表达您意图的代码。


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

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

…或者如果你关心性能:

1
2
3
4
5
6
7
var toArray = (function () {
    var slice = Array.prototype.slice;

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

您不希望在您的代码中使用slice.call构造…