问题 解除引用变量的闭包是否有用?


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

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 可能会在运行时更改。

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


7796
2017-11-27 20:09


起源

仅供参考,它会 .slice.call(arguments, 0)。 - pimvdb
jsperf.com 除非你对你正在创建的变量数量感到非常生气,否则我会认为这是浏览器环境中的微优化。 - Jared Farrish
... 要不就 [].slice.call( arguments )。 - Šime Vidas
仅供参考, a.b.c.d["e"].f 等于 a.b.c.d.e.f - Wojciech Bednarski
过早的微观优化是不好的。特别是如果没有真正的需要它。在图书馆,它可能没问题。 - ThiefMaster♦


答案:


“解除引用”实际上是一个令人困惑的词。不是那样,你就是这样 高速缓存 局部变量中的一些属性/方法。实际上,无论是访问随机对象上的某些属性/方法还是使用它,都没有区别 Array.prototype.slice。它使 很多 一旦访问那些深层嵌套的属性,就会感觉到 不止一次

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

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

特别是Internet Explorer <9和Firefox 3.5在进入(原型)链的每一步中都会导致严重的性能损失。


需要注意的一点是:不建议对对象方法使用本地缓存(就像使用对象方法一样) slice 方法)。许多物体使用 this 确定他们被称为的背景。在本地变量中存储方法会导致 this 被束缚 global object 要么 null。 因此,请务必使用这样的方法 method.call 手动设置上下文。


10
2017-11-27 20:13



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


如果您打算多次访问属性,请考虑将其分配给局部变量。但是,对于现代javascript引擎来说,这种微优化会产生很小的差异,最重要的是编写表达你意图的代码。


2
2017-11-27 20:16





对于这个特殊问题,你想要有一个实用功能:

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 构建你的代码......


0
2017-11-27 20:21