我正在考虑使用本机方法创建包含默认值的数组的方法,最后以
结束function pushMap(length, fill){
var a = [], b = [];
a.length = length;
b.push.apply(b,a);
return b.map(function(){return fill;});
}
期望它比while循环慢 2 或 3 倍,因为本机方法必须循环两次,而while循环只有一次,所以我比较了jsperf反对
function whileLengthNew(len, val) {
var rv = new Array(len);
while (--len >= 0) {
rv[len] = val;
}
return rv;
}
实际上 18 到 27 慢(在Ubuntu上使用Google Chrome进行测试,欢迎使用浏览器/操作系统)。
会发生什么导致如此大的差异?
答案 0 :(得分:2)
我希望这是由于两个主要因素:
内存分配 - whileLengthNew
首先创建一个正确大小的数组,然后对其进行操作,pushMap
使用map
一次创建一个元素的最终数组。这可能会导致多次分配,尤其是在源阵列很大的情况下。 (创建初始a
和b
数组的方式基本上是无关紧要的,因为map
正在构建一个新的数组以便返回 - 它实际上并没有改变{ {1}})
函数调用开销 - 在调用b
时,您正在为数组的每个元素调用一个函数。这涉及相当多的开销;设置激活记录和作用域链,堆栈操作以及返回返回值。 - 所有这些都可以访问函数中常量的变量。最重要的是,您已经设置了一个闭包,所以即使访问,map
变量也比fill
版本慢。
答案 1 :(得分:0)
我不是javascript专家,我没有贡献任何javascript引擎,所以以下只是一个猜测:
在pushMap
功能中,您有很多事情要发生
1.首先,你以一种可能非常低效的方式将var a
扩展到你想要的大小。 length
只是数组中的一个属性,因此底层实现具有更改属性时的回调,或者底层实现可以处理更改的长度属性,并在下次访问其中的某些内容时使用它。
2.创建var b
似乎效率更低,因为您正在调用反射类型方法apply
以使b
成为特定长度的数组。
3.然后你基本上以函数方式调用foreach循环,这可能比while循环慢一点,因为内部函数的开销(闭包我猜是因为它是JS)
如果您使用与创建var b
相同的方式创建var rv
,则可能会获得更均匀的结果。希望这可以帮助。 EDIT 当然在这种情况下不起作用,因为map只适用于数组的初始化值。这意味着这种方法较慢的另一个原因(并且OP在他的问题中提到了这一点)你正在初始化地图两次,一次是空值,再一次是你想要的值。
答案 2 :(得分:0)
你为每一个值进行不必要的函数调用,因此JavaScript虚拟机很难优化这个模式,你的数组也不会被内部视为一个简单的数组,而是复杂的数据结构,另一方面你在while循环中使用非常简单的数组访问模式,我怀疑你是否会使用带有rv.length的for循环作为停止条件它仍然会更快
答案 3 :(得分:0)
我认为调用map()与while循环的作用相同,此外还在每次迭代时调用函数。一般来说,函数调用非常慢。