我在jsperf中编写了一些测试用例,来测试使用Array.map
和其他替代方法时命名函数和匿名函数之间的区别。
http://jsperf.com/map-reduce-named-functions
(请原谅这个网址名称,这里没有测试Array.reduce
,我在完全确定我想要测试什么之前就已经给测试命名了)
一个简单的for/while循环显然是最快的,但我还是对Array.map
慢了10倍以上感到惊讶...
然后我尝试了Mozilla的polyfillhttps://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);
};
};
结果概述:
从最快到最慢:
- 对于简单/while循环(大致相同)
- Map3(我自己的实现)
- Map2(Mozilla polyfill)
Array.map
- for in
观察结果
有趣的是,命名函数通常比匿名函数快一点(约为5%)。但我注意到在Firefox中,使用命名函数时polyfill比较慢,但在Chrome中更快,但Chrome自己的map实现使用命名函数更慢...我进行了大约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倍(如我的测试所示),因为您需要在每个循环中检查属性是否存在...
结论
如果考虑到不同的浏览器表现略有不同,那么命名函数和匿名函数之间并没有太大区别。
归根结底,我们不应该过于微观优化,但我发现这很有趣 :)
Array.map
仍然比简单的 for 循环慢得多。无论如何,正如之前的评论所提到的,我的测试偏离了我的原始意图,因此请以此为参考 :P - Populus