为什么一个比另一个更好呢?
[].map.call(...)
Array.prototype.map.call(...)
在jsPerf中进行快速测试表明,Array.prototype方式更有表现力,尽管我在某个地方读到了jsPerf结果可能具有欺骗性。不是为了讨论jsPerf,而是想了解一下为什么一个会比另一个更好。谢谢!
发布于 2016-02-24 12:42:31
在没有恶作剧的情况下,[].map
和Array.prototype.map
的值是相同的。表达式[].map
涉及(至少在概念上;它可以被优化,可能的话)构造一个新的数组实例,这样可能会产生(非常小的)性能影响。
表达式[].map
创建一个新的空数组,然后引用它的"map“属性。除非添加"map“属性,否则数组实例不具有”map“属性,因此在对象本身上找不到它。因此,运行时将检查原型链上的下一个东西,当然是Array.prototype
对象。运行时将在那里找到一个"map“属性--特别是Array.prototype.map
。这就是为什么他们是一样的。
{}.toString
和Object.prototype.toString
具有类似的等价性。使用模式的主要区别可能是,{}.toString
在表达式的开头出现时可能会引起问题,因为在这种情况下,前面的{
将被视为语句块{
,而不是对象初始化{
。但是,{}.toString
的典型用法并不是很可能需要启动表达式。因此
console.log({}.toString.call(someMysteryObject));
工作得很好
console.log(Object.prototype.toString.call(someMysteryObject));
就性能而言,在.map()
的情况下,在使用该方法时隐含的函数调用的开销几乎肯定会完全克服两种方法在开始时查找对.map()
函数的引用之间的性能差异。
发布于 2016-02-24 12:53:17
基准测试
1.背景
我做了一个基本的基准测试,看看我是否能发现这四种不同语句之间的性能差异:
dataSet.map(function)
dataSet.map.call(dataSet, function)
[].map.call(dataSet, function)
Array.prototype.map.call(dataSet, function)
2.方法
我在一个孤立的沙箱中执行了这四条语句中的每条语句1,000,000次,并比较了之后的处理时间。
我使用以下计时器函数来确定处理时间:
var timer = function(name) {
var start = new Date();
return {
stop: function() {
var end = new Date();
var time = end.getTime() - start.getTime();
console.log('Timer:', name, 'finished in', time, 'ms');
}
}
};
3.试验环境
我在一台2年前使用英特尔i7四核CPU的ASUS笔记本电脑上进行了测试。
我在Linux Ubuntu中进行了测试,在以下两个浏览器上进行了测试:
4.设想情况
4.1。dataSet.map(function)
场景
var t = timer('Benchmark'); // <-- START BENCHMARK
var reformattedArray;
var rObj;
var kvArray = [{key:1, value:10}, {key:2, value:20}, {key:3, value: 30}];
for(var i = 0; i < 1000000; i++) {
reformattedArray = kvArray.map(function(obj){
rObj = {};
rObj[obj.key] = obj.value;
return rObj;
});
}
t.stop(); // <-- STOP BENCHMARK
(另见这个小屁孩)
4.2。dataSet.map.call(dataSet, function)
场景
var t = timer('Benchmark'); // <-- START BENCHMARK
var reformattedArray;
var rObj;
var kvArray = [{key:1, value:10}, {key:2, value:20}, {key:3, value: 30}];
for(var i = 0; i < 1000000; i++) {
reformattedArray = kvArray.map.call(kvArray, function(obj){
rObj = {};
rObj[obj.key] = obj.value;
return rObj;
});
}
t.stop(); // <-- STOP BENCHMARK
(另见这个小屁孩)
4.3。[].map.call(dataSet, function)
场景
var t = timer('Benchmark'); // <-- START BENCHMARK
var reformattedArray;
var rObj;
var kvArray = [{key:1, value:10}, {key:2, value:20}, {key:3, value: 30}];
for(var i = 0; i < 1000000; i++) {
reformattedArray = [].map.call(kvArray, function(obj){
rObj = {};
rObj[obj.key] = obj.value;
return rObj;
});
}
t.stop(); // <-- STOP BENCHMARK
(另见这个小屁孩)
4.4。Array.prototype.map.call(dataSet, function)
场景
var t = timer('Benchmark'); // <-- START BENCHMARK
var reformattedArray;
var rObj;
var kvArray = [{key:1, value:10}, {key:2, value:20}, {key:3, value: 30}];
for(var i = 0; i < 1000000; i++) {
reformattedArray = Array.prototype.map.call(kvArray, function(obj){
rObj = {};
rObj[obj.key] = obj.value;
return rObj;
});
}
t.stop(); // <-- STOP BENCHMARK
(另见这个小屁孩)
5.中期成果
我没有注意到这四种场景之间的性能差异,但是我确实注意到Firefox比Chrome快4倍(对于这两种场景)。
更确切地说,Chrome大约需要1秒来处理每个场景,而Fixefox只需要0.25秒。
为了评估这些浏览器差异是否特定于map
方法,我进一步简化了测试。
6.情景v2
6.1。场景v2用于dataSet.map(function)
var t = timer('Benchmark'); // <-- START BENCHMARK
var reformattedArray;
var rObj;
var kvArray = [{key:1, value:10}, {key:2, value:20}, {key:3, value: 30}];
for(var i = 0; i < 1000000; i++) {
kvArray.map(function(obj){
return rObj;
});
}
t.stop(); // <-- STOP BENCHMARK
(另见这个小屁孩)
6.2。场景v2用于dataSet.map.call(dataSet, function)
var t = timer('Benchmark'); // <-- START BENCHMARK
var reformattedArray;
var rObj;
var kvArray = [{key:1, value:10}, {key:2, value:20}, {key:3, value: 30}];
for(var i = 0; i < 1000000; i++) {
kvArray.map.call(kvArray, function(obj){
return rObj;
});
}
t.stop(); // <-- STOP BENCHMARK
(另见这个小屁孩)
6.3。场景v2用于[].map.call(dataSet, function)
var t = timer('Benchmark'); // <-- START BENCHMARK
var reformattedArray;
var rObj;
var kvArray = [{key:1, value:10}, {key:2, value:20}, {key:3, value: 30}];
for(var i = 0; i < 1000000; i++) {
[].map.call(kvArray, function(obj){
return rObj;
});
}
t.stop(); // <-- STOP BENCHMARK
(另见这个小屁孩)
6.4。场景v2用于Array.prototype.map.call(dataSet, function)
var t = timer('Benchmark'); // <-- START BENCHMARK
var reformattedArray;
var rObj;
var kvArray = [{key:1, value:10}, {key:2, value:20}, {key:3, value: 30}];
for(var i = 0; i < 1000000; i++) {
Array.prototype.map.call(kvArray, function(obj){
return rObj;
});
}
t.stop(); // <-- STOP BENCHMARK
(另见这个小屁孩)
7.最后结果
现在,Chrome运行这些场景需要大约0.275秒,Firefox大约需要0.035秒。这意味着火狐比Chrome快7倍多。
同样,在使用相同的浏览器时,四种场景中的每一种都没有明显的性能差异。
https://stackoverflow.com/questions/35612650
复制相似问题