为什么 Array.splice() 这么慢?

Why is Array.splice() so slow?

我最近看到了这个基准:http://jsperf.com/remove-element-splice-vs-move-and-pop

我注意到 Array.splice() 比遍历元素的 for 循环慢几个数量级。这让我想知道为什么 Array.splice() 这么慢。

所以特意过来问问大家:为什么Array.splice()这么慢?

那个benchmark有一个谬误:.splice保留了数组中元素的顺序,因此需要移动一半的元素,直到移除产生的空洞被筛选到最后并且可以通过调整数组大小来删除。由此可见,.splice线性时间内工作。

反之,这段代码:

array[500000] = array[array.length-1];
array.pop();

将最后一个元素与要删除的元素交换,并缩短 1 个元素的数组,该操作可以在 恒定时间 内完成。从技术上讲,上面的代码片段甚至没有实现声明的目标,因为 它改变了数组中元素的顺序 (!)。比较:

> array.splice(500000,1)
> console.log(array[500000])
500001

与:

> array[500000] = array[array.length-1];
> array.pop();
> console.log(array[500000])
999999

拼接将 return 你的整个数组,减去删除的项目。因此,对于基准示例中的 1 个元素,您必须将其他 499999 个元素复制到一个新数组中。但是 pop 只需要将数组缩短为 一个元素。

以下是来自真实项目(不是基准)的一些措施。我有一个数组中的对象列表,最后不得不得到一个较小的子集。在这里显示的案例中,列表恰好有 17,000 个项目,而我们恰好只需要 7 个。

我的第一个方法是遍历数组并使用 splice 删除那些不需要的。 Firefox 在这种方法上存在重大问题,需要 12 秒才能完成 Chrome 在 0.09 秒内完成的工作!第二种方法是反向迭代,做同样的事情。第三个是将想要的对象复制到一个新数组中。

              Splice Forward   Splice Reverse   Copy to Array   (time in milliseconds)
Chrome 51             91              64             47
IE 11.0.31           309             144             31
Firefox 47        12,544              61             21

最终,所有浏览器的复制速度都快得多。

但是,如果您确实需要 splice,反向执行可能会快得多。