JavaScript数组合并的性能边界由引擎底层机制决定:扩展运算符受65536参数限制易抛RangeError,concat()无此限制;小至1000元素即现性能差异,多数组合并时concat更高效。

JavaScript 中数组合并的性能边界不是模糊的经验值,而是由引擎底层机制决定的硬限制和可观测拐点。选 concat() 还是 扩展运算符([...arr1, ...arr2]),关键不在写法是否简洁,而在于“多大时会出问题”。
参数数量限制:65536 是一道真实红线
扩展运算符本质是把数组元素逐个展开为函数调用参数。V8、SpiderMonkey 等主流引擎对单次函数调用的参数个数有严格上限,实测普遍在 65536 左右。一旦任一被展开的数组长度 ≥ 65536,就会直接抛出 RangeError: Maximum call stack size exceeded。
- concat() 完全不触碰该限制——它只接收数组引用作为参数,无论数组多长都安全
- 这个边界与数据类型无关,数字、字符串、对象数组都会触发
- 哪怕只是合并两个 40000 元素的数组,
[...a, ...b]也已接近临界,叠加其他参数更易越界
性能拐点:1000 元素起就有可测差异
小数组(
- 合并两个基本类型数组:
– 1 万个元素:concat 快约 15%
– 10 万个元素:快 20%–30%,内存峰值低 25% 以上
– 100 万个元素:concat 耗时约 50ms,扩展运算符常超 200ms,且 GC 压力明显升高 - 原因在于:扩展运算符内部类似多次
push(),可能触发多次动态扩容(如 2→4→8→…),每次都要复制已有数据;
concat() 可预估总长度,一次性申请连续内存块,V8 对其做了深度底层优化
对象数组场景:稳定性仍是 concat 优势
当元素是对象时,两者都只做浅拷贝,绝对耗时差距缩小。但扩展运算符仍有隐患:
立即学习“Java免费学习笔记(深入)”;
- 每个数组都要创建迭代器对象,对象越多,临时对象分配越频繁,GC 更容易被触发
- 若合并过程中含中间计算(如
[...arr1.filter(x => x), ...arr2.map(y => y)]),迭代器叠加进一步放大开销 - concat() 的单次调用模型更可控,适合嵌入高频逻辑(如 React 渲染循环、Canvas 动画帧)
多数组合并:concat 天然支持,扩展需额外成本
合并 3 个及以上数组时,行为差异立刻显现:
-
arr1.concat(arr2, arr3, arr4)—— 一次调用,语义清晰,无额外开销 -
[...arr1, ...arr2, ...arr3, ...arr4]—— 等价于四次独立展开,迭代器创建 ×4,扩容机会 ×4 - 若改用
[arr1, arr2, arr3].flat(),还要额外执行扁平化遍历,性能更差



















