有多个数组a, b, c,需求是将多个数组合并成一个:

1
2
3
let a = [1, 2, 3]
let b = [4, 5, 6]
let c = [7, 8, 9]
  1. concat()
    合并多个数组,不影响原数组(会造成内存浪费),不能处理嵌套数组。

    1
    2
    3
    4
    const r = a.concat(b)
    a // [1, 2, 3]
    b // [4, 5, 6]
    r // [1, 2, 3, 4, 5, 6]

    如果 a 数组有10000个元素, b 数组也有有10000个元素, 那么数组r就有20000个元素, 这种方式占用了2倍的内存。a = b = null;就会被垃圾回收机制回收。

  2. 基于for循环 - push()
    没有concat的内存浪费,看上去土而且不好维护, 只能合并两个数组,会改变原数组,不能处理嵌套数组。

1
2
3
4
5
for (let i in b) {
a.push(b[i])
}
a // [1, 2, 3, 4, 5, 6]
b // [4, 5, 6]
  1. apply
    简洁高效,能实现多个数组合并, 会改变原数组, 并且能够实现深度嵌套。
1
2
3
a.push.apply(a, b)
a // [1, 2, 3, 4, 5, 6]
b // [4, 5, 6]
  1. 更优美的push
    多个数组合并, 会改变原数组, 效率比较高
1
2
3
4
5
// es6
a.push(...b, ...c)
a // [1, 2, 3, 4, 5, 6]
b // [4, 5, 6]
c // [7, 8, 9]

为什么 Array.concat 这么慢?
合并拥有大小为 10 的数组 10000 次,.concat 的速度为 0.40 ops/sec(操作每秒),而 .push 的速度是 378 ops/sec。也就是说 push 比 concat 快了整整 945 倍!这种差异可能不是线性的,但在这种小规模数据量上已经很明显了。

这与它们的运行机制有很大的关系:在合并数组的时候,.concat 创建了一个新的数组,而 .push 只是修改了第一个数组。这些额外的操作(将第一个数组的元素添加到返回的数组里)就是拖慢了 .concat 速度的关键。