应避免用 push.apply 或扩展运算符合并大数组,因其会因参数超限导致栈溢出;正确做法是分块调用 push,如每 5 万项切片一次,确保单次参数不超引擎限制。

push.apply 会爆栈,别用它合并大数组
直接调用 arr1.push.apply(arr1, arr2) 在数组长度超过几万时大概率触发 RangeError: Maximum call stack size exceeded。这是因为 apply 把第二个参数展开为函数调用的独立实参,V8 等引擎对参数数量有限制(通常约 10 万以内),而巨量数组(比如 50 万项)一展开就超限。
扩展运算符 + push 是语法糖,底层仍走 apply 路线
arr1.push(...arr2) 看似简洁,但和 push.apply 本质相同:引擎仍需将 arr2 的每一项作为独立参数传入 push。所以它在数组较大时同样会崩溃,不是“更现代所以更安全”的替代方案。
真正安全的合并方式:分块调用 push
核心思路是避免一次性传入过多参数,把大数组切片后多次调用 push。V8 对单次调用参数上限约 65536,保险起见按 5 万一项切片:
function pushChunked(target, source) {
const chunkSize = 50000;
for (let i = 0; i < source.length; i += chunkSize) {
target.push(...source.slice(i, i + chunkSize));
}
}
使用示例:pushChunked(bigArray1, bigArray2)。注意 slice 会产生临时子数组,内存开销可控(只保留当前块);若追求极致内存,可用 for 循环手动逐项 push,但性能略低。
超大规模场景优先考虑 concat 或直接赋值
如果只是需要合并结果、不强求复用原数组,const merged = arr1.concat(arr2) 更稳妥——它不依赖 push,无栈溢出风险,且现代引擎对 concat 有优化;若允许替换原引用,甚至可直接 arr1 = [...arr1, ...arr2](此式在 V8 中已被优化为高效内存拷贝,但注意它创建新数组)。
真正容易被忽略的是:**分块合并时,slice 的结束索引必须用 i + chunkSize 而非硬编码,否则最后一块可能越界或漏项**。

















