数组的concat和unshift有性能差别么?

如题,假设有这样一个结构

interface item {
  name: string,
  isOK: boolean
}

let items: item[] = [
    {name: 'Example', isOK: true}
];

现在要把一个新项目添加到items的第一项,可以有两种方法:

items.unshift(newItem);
items = Array(newItem).concat(items);

两个方法的结果都是一样的,如果这样的数据以后越累越多,请问concat和unshift的性能上会有差别么?

我觉得可能concat会慢一些,因为每次都要处理一个数组过来,但是我又不知道如何印证这个猜想,烦请了解的朋友科普一下。谢谢!

===============================================================================

补充问题:
我看了一下几位朋友的回答,刚才得到回复感觉太兴奋了,没太注意我自己的需求,仔细一看我发现还是和我的提问有所偏差,这里补充一下:

===============================================================================

@李十三 回答的情况不太相同的是我是事先有那么多数量个元素,我只是要在第一个位置上插入一个元素:

const itemCount = 100000;
console.log(`当前数组一共有${itemCount}个元素`);

interface item {
  name: string,
  isOK: boolean
}

let items: item[] = [];
for(let i = 0; i < itemCount; i++){
    items.push({ name: `item${i}`, isOK: false});
}

let newItem: item = {
  name: 'New First Item!',
  isOK: true
}

function byUnshift(list: item[], item: item){
  console.log('unshift性能测试');
  list.unshift(item);
}

function byConcat(list: item[], item: item){
  console.log('concat性能测试');
  list = Array(item).concat(list);
}

function perfTest(func: Function){
  const label: string = '耗费时间(毫秒)';
  console.time(label);
  
  func(items, newItem);

  console.timeEnd(label);
}

perfTest(byUnshift);
perfTest(byConcat);

我这里先测试了100000个元素的插入情况,反馈结果如下:

list目前有100000个元素
unshift性能测试
耗费时间(毫秒): 1.738ms
concat性能测试
耗费时间(毫秒): 1.746ms

然后我又加了俩0……

list目前有10000000个元素
unshift性能测试
耗费时间(毫秒): 20.116ms
concat性能测试
耗费时间(毫秒): 331.053ms

我又测试了100个的性能

list目前有100个元素
unshift性能测试
耗费时间(毫秒): 0.461ms
concat性能测试
耗费时间(毫秒): 0.148ms

然后我发现好像元素个数少的话concat就会好一些,但是随着元素个数增加,unshift的优势就越来越明显了。

我就是想知道这是为啥……

===============================================================================

补充2:
@XboxYan 给了一个想法,认为先reverse再push然后再reverse是最快的。

===============================================================================
我测试了一下:

function reversePushReverse(list: item[], item: item){
    console.log('reverse->push->reverse性能测试');
    list = list.reverse();
    list.push(item);
    list = list.reverse();
    }
}

测试结果如下:

******************第1次测试开始,本次生成10个样例******************
unshift性能测试
耗费时间(毫秒): 0.384ms
concat性能测试
耗费时间(毫秒): 0.125ms
reverse->push->reverse性能测试
耗费时间(毫秒): 0.170ms
******************第0次测试结束******************


******************第2次测试开始,本次生成100个样例******************
unshift性能测试
耗费时间(毫秒): 0.072ms
concat性能测试
耗费时间(毫秒): 0.070ms
reverse->push->reverse性能测试
耗费时间(毫秒): 0.065ms
******************第1次测试结束******************


******************第3次测试开始,本次生成1000个样例******************
unshift性能测试
耗费时间(毫秒): 0.063ms
concat性能测试
耗费时间(毫秒): 0.072ms
reverse->push->reverse性能测试
耗费时间(毫秒): 0.063ms
******************第2次测试结束******************


******************第4次测试开始,本次生成10000个样例******************
unshift性能测试
耗费时间(毫秒): 0.157ms
concat性能测试
耗费时间(毫秒): 0.164ms
reverse->push->reverse性能测试
耗费时间(毫秒): 0.123ms
******************第3次测试结束******************


******************第5次测试开始,本次生成100000个样例******************
unshift性能测试
耗费时间(毫秒): 1.317ms
concat性能测试
耗费时间(毫秒): 2.065ms
reverse->push->reverse性能测试
耗费时间(毫秒): 3.261ms
******************第4次测试结束******************


******************第6次测试开始,本次生成1000000个样例******************
unshift性能测试
耗费时间(毫秒): 5.075ms
concat性能测试
耗费时间(毫秒): 10.130ms
reverse->push->reverse性能测试
耗费时间(毫秒): 12.165ms
******************第5次测试结束******************
阅读 5.3k
5 个回答

图片描述

你可以建立一个包含1万项的数组 例如const newArry = new Array(10000).fill('test')
然后来一个for循环 每次都将这个数组的一个test推入到你的items数组里 这个循环完了 再来一个循环用另外一种方式
如果上一个循环用unshift 这个循环就用concat
在循环开始前new Date()一个时间 保存起来 循环结束后用new Date()获得一个新的时间 用新时间减去旧时间 就能获得运行时间 两相对比就知道哪个快 哪个慢了

在同样操作而言,concat 的性能远胜 unshift 性能测试

可以通过reserve翻转,然后push,然后reserve翻转,应该是性能最好的

我觉得似乎可以理解了……不知道这样理解对不对……

Array(item).concat(list)相当于是将这个数组和新生成的数组合并,这样是生成两次数组:

  1. list转换为Array,生成了一个只有item一个元素的数组,因为内容少,所以生成速度还算快
  2. 生成了[item, ...] 这个过程很耗时

reverse(list); list.push(item); reverse(list);相当于前后生成了两次数组后再push:

  1. reverse 生成了一个 [-1...0]的数组,这个过程很耗时
  2. push为数组增加一个新元素 [-1 ... 0, item] 这个过程非常快
  3. 再次reverse 生成了 [item, 0, ... -1] 的数组,这个过程很耗时

list.unshift(item)它只遍历一次数组:

  1. 先将list.length增加了1
  2. 遍历了一次数组并将元素后移, 这个过程非常费时
  3. list[0] = item 这个最省时

所以当元素数量越来越多的时候,unshift虽然本质上很慢,但是与前两个相比,它只遍历一次元素,且不生成新元素,所以元素超过10万个以后,反而是unshift这种一心一意的方法最快了……