JavaScript数组合并与拆分操作代码实例
深入讲解JavaScript数组合并与拆分操作,涵盖扩展运算符、concat、push、slice、splice的核心用法、边界细节、浅拷贝机制及分批处理实战代码实例。
假设你正在开发一个电商后台的订单中心:前端需要将用户勾选的“自营商品列表”与“第三方商户商品列表”拼接成一个统一的发货单,同时在批量向后台接口同步数据时,由于单次请求体积限制,又必须将包含上千条订单的一维数组切分为每组50条的批次数组进行并发分发。类似这种数组的合并拼接与按需切分,是前端业务系统与 Node.js 服务端处理集合数据时最基础、最高频的操作。本文将围绕这两个核心诉求,系统化解析 JavaScript 中常用的合并与拆分方法,配合具体代码实例与内存机制分析,帮助你在实际项目中准确选型。
一、JavaScript 数组合并操作与实战代码
数组合并是指将两个或多个数组中的元素组合在一起。在具体开发中,关键决策点在于:是否允许修改现有数组以节省内存分配,还是需要返回一个不影响原数据的纯净新数组。
1. 扩展运算符(Spread Operator ...)
自 ES6 引入扩展运算符后,使用字面量解构已成为现代 JavaScript 合并数组的首选方式。其语法直观,阅读成本极低,且天然支持在合并过程中向任意位置穿插单独元素。
// 示例:使用扩展运算符合并商品列表
const domesticItems = ['图书', '文具'];
const importedItems = ['咖啡豆', '奶粉'];
// 合并两个数组,并允许在指定位置插入新项
const allItems = [...domesticItems, '促销赠品', ...importedItems];
console.log('合并后的商品列表:', allItems);
// 输出: ['图书', '文具', '促销赠品', '咖啡豆', '奶粉']
console.log('原数组 domesticItems 是否受影响:', domesticItems);
// 输出: ['图书', '文具'](原数组保持不变)
2. 经典方法 concat()
在需要兼容旧版本执行环境或纯函数式编程风格中,Array.prototype.concat() 依然是标准且可靠的方案。它会返回一个合并后的新浅拷贝数组,不改变参与合并的任何原数组。此外,concat 支持传入非数组项,会自动将其作为单项追加。
// 示例:使用 concat 进行多源数组拼接
const groupA = [101, 102];
const groupB = [201, 202];
const groupC = [301];
const combined = groupA.concat(groupB, groupC, 401);
console.log('拼接结果:', combined);
// 输出: [101, 102, 201, 202, 301, 401]
3. 原地修改合并:push.apply() 与 push(...items)
当处理成千上万条记录的超大数组时,如果频繁创建新数组,会引发频繁的垃圾回收(GC)并占用翻倍的内存。若业务场景明确要求“将 B 数组直接吸收并入 A 数组且保持 A 的引用不变”,则应使用原地修改方法。
// 示例:原地修改合并
const targetList = ['任务A', '任务B'];
const incomingTasks = ['任务C', '任务D'];
// 方式一:现代语法 push + 解构
targetList.push(...incomingTasks);
console.log('目标数组内容:', targetList);
// 输出: ['任务A', '任务B', '任务C', '任务D']
// 方式二:防止参数过多导致调用栈溢出时的安全批处理合并
function appendInBatches(target, source, batchSize = 1000) {
for (let i = 0; i < source.length; i += batchSize) {
const chunk = source.slice(i, i + batchSize);
target.push(...chunk);
}
}
二、JavaScript 数组拆分与截取操作代码实例
数组拆分与截取是将一个大数组提取出其中一部分或分割为多个片段。最核心的方法是 slice() 和 splice()。虽然名称仅有一字之差,但运行机制完全不同。
1. 非破坏性截取:slice(start, end)
slice() 接收起始索引与结束索引,返回一个由截取元素组成的新数组。其关键规则是:包含起始索引,但不包含结束索引(前闭后开区间 [start, end))。原数组完全不受影响。
// 示例:使用 slice 提取固定范围项
const dataset = ['A', 'B', 'C', 'D', 'E', 'F'];
// 提取索引 1 到 4 之间的元素(不包含索引 4)
const middleSlice = dataset.slice(1, 4);
console.log('截取切片:', middleSlice);
// 输出: ['B', 'C', 'D']
// 支持负数索引:提取最后 2 项
const lastTwo = dataset.slice(-2);
console.log('末尾两项:', lastTwo);
// 输出: ['E', 'F']
console.log('原数组未受任何破坏:', dataset);
// 输出: ['A', 'B', 'C', 'D', 'E', 'F']
2. 破坏性就地拆分:splice(start, deleteCount, ...items)
splice() 是一个多功能原位修改方法。它接收起始位置、要删除的元素个数以及可选的新增项。其返回值是被移除的元素组成的新数组,而原数组被直接修改。
// 示例:使用 splice 原地移出指定元素
const queue = ['任务1', '任务2', '任务3', '任务4'];
// 从索引 1 开始,连续移除 2 个元素
const processedTasks = queue.splice(1, 2);
console.log('被剥离的子数组:', processedTasks);
// 输出: ['任务2', '任务3']
console.log('剩余的原数组:', queue);
// 输出: ['任务1', '任务4'] (原数组已经被裁剪变短)
3. 业务高频实例:将一维大数组按固定步长分块(Chunking)
在前端分页渲染、Excel 数据批量导出或并发请求限制时,将包含上百或上千条元素的大数组按固定尺寸 size 拆分成二维数组是非常通用的需求。利用 slice() 可以写出高内聚、易测试的纯函数。
// 实例:将大数组拆分为等长二维子数组
function chunkArray(array, size) {
if (!Array.isArray(array) || size <= 0) {
return [];
}
const result = [];
for (let i = 0; i < array.length; i += size) {
// 每次从 i 截取到 i + size,即便最后一段不足 size,slice 也会自动处理边界
result.push(array.slice(i, i + size));
}
return result;
}
// 模拟待同步的数据清单
const orders = [1001, 1002, 1003, 1004, 1005, 1006, 1007];
const batches = chunkArray(orders, 3);
console.log('拆分批次结果:', batches);
// 输出:
// [
// [1001, 1002, 1003],
// [1004, 1005, 1006],
// [1007]
// ]
三、核心注意事项与避坑指南
- 浅拷贝与深拷贝陷阱:无论是扩展运算符
...还是concat()、slice(),对于数组内的引用类型元素(对象、嵌套数组),复制的都仅是指向堆内存的引用地址。如果在新数组中修改了对象的内部字段,原数组中对应的对象也会被同步篡改。若需要完全隔离,需先使用深拷贝(如structuredClone())。 - 解构操作的参数上限问题:在极大数据量(例如十万级或百万级元素)下使用
arr1.push(...arr2)或arr1.push.apply(arr1, arr2)时,解构会作为函数调用实参入栈,极易触发 JavaScript 引擎抛出RangeError: Maximum call stack size exceeded。超大数据合并应使用for循环或分块迭代方式写入。 splice的索引越界与负数安全:splice传入负数索引时会从末尾向前定位。如果起始索引绝对值大于数组长度,则起始位置重置为 0;如果deleteCount被省略,则会从起始索引一直删除到数组末尾。在编写动态业务逻辑时,必须显式传入删除数量,避免误清空整个列表。
四、总结
处理 JavaScript 数组的合并与拆分时,首要准则是区分“纯函数操作”与“破坏性原地修改”:
- 在 React、Vue 等数据驱动视图的现代框架中,优先推崇不可变数据思想,合并推荐使用
[...arr1, ...arr2],拆分推荐使用arr.slice(),以确保状态变更的可追溯性。 - 在高性能吞吐、持续消费队列或内存受限的环境中,合理利用
arr.push(...items)和arr.splice()进行原地维护,能够有效减少对象分配与垃圾收集负担。
结合数据量级和业务边界合理选型,才能写出兼具可读性、鲁棒性与高效性能的代码。
什么时候该用JS构造器:与工厂模式、字面量的选择对比
2026-11-05 16:18:22
推荐几款轻量级JS照片墙开源库及对比
2026-11-05 15:56:19
JavaScript递归写法有哪些常见陷阱及避免方法
2026-11-05 14:53:38
JS数组浅拷贝与深拷贝怎么选?场景与方法总结
2026-11-05 14:41:02
p5.js 中 setup() 和 draw() 函数的执行机制详解
2026-11-05 12:32:38








![JS创建二维数组:为什么Array(n).fill([])会导致数据联动](https://img.javascript.cn/tit/articles/13236/20261102/f618c991891ff37efb12df6af2ce0ccb0da8779a907fe1d2f7275d60c84fdd77.webp)