为什么负数组索引要比正数组索引慢得多?

时间:2019-02-12 16:30:19

标签: javascript arrays

这是一个简单的JavaScript性能测试:

const iterations = new Array(10 ** 7);

var x = 0;
var i = iterations.length + 1;
console.time('negative');
while (--i) {
	x += iterations[-i];
}
console.timeEnd('negative');

var y = 0;
var j = iterations.length;
console.time('positive');
while (j--) {
	y += iterations[j];
}
console.timeEnd('positive');

第一个循环从10,000,000向下计数到1,并在每次迭代中使用负索引访问长度为1000万的数组。因此它从头到尾遍历整个数组。

第二个循环从9,999,999向下计数到0,并在每次迭代时使用正索引访问同一数组。因此它反向通过数组。

在我的PC上,第一个循环需要6秒钟以上的时间才能完成,但是第二个循环只需要400毫秒左右的时间。

为什么第二个循环比第一个循环快?

2 个答案:

答案 0 :(得分:5)

因为iterations[-1]的求值结果为undefined(这很慢,因为它必须沿着整个原型链进行,并且不能走快速路径),所以也要对NaN进行数学运算总是很慢,因为这是不常见的情况。

还用数字初始化iterations将使整个测试更加有用。

专业提示:如果您尝试比较两个代码的性能,则它们最后都应该导致相同的操作...


关于性能测试的一些常用字眼:

性能是当今编译器的工作,由编译器优化的代码将始终比您尝试通过某些“技巧”优化的代码快。因此,您应该编写编译器可能会优化的代码,即在每种情况下,其他人编写的代码(如果这样做,您的同事也会喜欢您)。从引擎的角度来看,优化是最有益的。因此我会写:

 let acc = 0;
 for(const value of array) acc += value;

 // or
 const acc = array.reduce((a, b) => a + b, 0);

但是最终这只是一个循环,如果循环执行不佳,您不会浪费很多时间,但是如果整个算法执行不佳,您将浪费很多时间(时间复杂度O(n²)或者更多)。专注于重要的事情,而不是循环。

答案 1 :(得分:1)

要详细说明Jonas Wilms的答案,Javascript不适用于否定索引(与Python等语言不同)。

iterations[-1]等于iteration["-1"],后者在数组对象中查找名为-1的属性。这就是iterations[-1]的评估结果为undefined的原因。