Array.map 的 Javascript 性能

标签 javascript performance jsperf

刚刚在 jsperf 中编写了一些测试用例,以测试在使用 Array.map 和其他替代方案时命名函数和匿名函数之间的区别。

http://jsperf.com/map-reduce-named-functions

(请原谅url名称,这里没有Array.reduce的测试,我在完全决定要测试什么之前命名测试)

一个简单的 for/while 循环显然是最快的,尽管 Array.map 慢了 10 倍以上,但我仍然感到惊讶......

然后我尝试了 mozilla 的 polyfill https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map#Polyfill

Array.prototype.map = function(fun /*, thisArg */)
{
    "use strict";

    if (this === void 0 || this === null)
        throw new TypeError();

    var t = Object(this);
    var len = t.length >>> 0;
    if (typeof fun !== "function")
        throw new TypeError();

    var res = new Array(len);
    var thisArg = arguments.length >= 2 ? arguments[1] : void 0;
    for (var i = 0; i < len; i++)
    {
        // NOTE: Absolute correctness would demand Object.defineProperty
        //       be used.  But this method is fairly new, and failure is
        //       possible only if Object.prototype or Array.prototype
        //       has a property |i| (very unlikely), so use a less-correct
        //       but more portable alternative.
        if (i in t)
            res[i] = fun.call(thisArg, t[i], i, t);
    }

    return res;
};

然后我尝试了一个我自己写的简单实现...

Array.prototype.map3 = function(callback /*, thisArg */) {
    'use strict';
    if (typeof callback !== 'function') {
        throw new TypeError();
    }

    var thisArg = arguments.length >= 2 ? arguments[1] : void 0;

    for (var i = 0, len = this.length; i < len; i++) {
        this[i] = callback.call(thisArg, this[i], i, this);
    };
};

结果总结:

从最快到最慢:

  1. 对于simple/while(差不多)
  2. Map3(我自己的实现)
  3. Map2(Mozilla polyfill)
  4. Array.map
  5. 为了在

观察

一个有趣的注意事项是命名函数通常比使用匿名函数快一点(大约 5%)。但我注意到 polyfill 在 firefox 中使用命名函数速度较慢,但​​在 chrome 中速度更快,但是 chrome 自己的映射实现使用命名函数速度较慢......我每个测试了大约 10 倍,所以即使它不是完全密集的测试(哪个 jsperf已经这样做了),除非我的运气那么好,否则它应该足以作为指导。

此外,在我的机器上,chrome 的 map 功能比 firefox 慢 2 倍。完全没想到。

而且... firefox 自己的 Array.map 实现比 Mozilla Polyfill 慢...哈哈

我不确定为什么 ECMA-262 规范声明 map 可以用于数组以外的对象 (http://www.ecma-international.org/ecma-262/5.1/#sec-15.4.4.19)。这使得整个 map 功能慢了 3-4 倍(如我的测试所示),因为您需要在每个循环中检查属性是否存在...

结论

如果您认为不同浏览器的性能略有不同,那么命名函数和匿名函数之间并没有太大区别。

归根结底,我们真的不应该进行太多的微优化,但我发现这很有趣 :)

最佳答案

首先,这不是一个公平的比较。正如您所说,正确的 javascript 映射能够使用对象,而不仅仅是数组。所以你基本上是在比较两个完全不同的函数和不同的算法/结果/内部工作原理。

当然,正确的 javascript 映射速度较慢 - 它旨在处理更大的域,而不是数组上的简单 for。

关于Array.map 的 Javascript 性能,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22182454/

相关文章:

javascript - JSPerf 测试结果随着测试运行而变慢?

javascript - 递归函数的奇怪 jsPerf 行为

javascript - 输入文本按时间间隔重新加载

javascript - 如果数组中的值存在,如何获取数组。 jQuery

javascript - 如何顺时针旋转物体?

c 中的 case 语句效率

sql-server - 合并与选择比插入更新性能比较

javascript - Javascript、倒计时、链接删除

c - 如何处理条件初始化,这是一种好的做法吗?

javascript - 解释这个 JsPerf.com 结果