1. slice 的基本用法
1.1 基本语法
在 JavaScript 中,slice 是用于从一个数组中截取子数组的非破坏性方法。它从 start(包含)到 end(不包含)提取元素,并返回一个新的数组。本文聚焦于 JS 数组截取方法全解析:slice 与 splice 的用法、适用场景及性能对比,帮助开发者理解如何在日常编码中选择正确的方法。
返回值是一个新数组,原数组不被修改,这是 slice 与就地修改的 splice 的本质区别之一。
const arr = [1, 2, 3, 4, 5];
const sub = arr.slice(1, 3); // [2, 3]
console.log(arr); // [1, 2, 3, 4, 5]
console.log(sub); // [2, 3]
负数索引、省略结束位置等用法使得 slice 的边界更加灵活。若 end 省略,则截取到数组末尾;若 start 为负数,则从末尾计数;此特性在处理类数组对象时也有帮助。
1.2 边界与行为深入
当 start 比 end 大时,slice 会返回一个空数组,但不会修改原数组。这一点对链式操作和防御性编程尤为重要。
在实际开发中,slice 常用于快速提取子数组,且不需要担心副作用,适合 Immutable 风格的工作流。

2. splice 的基本用法
2.1 基本语法
与 slice 不同,splice 是一个破坏性方法,会直接修改原数组。它的返回值是被删除元素组成的新数组,便于后续处理。
const arr = [1, 2, 3, 4, 5];
const removed = arr.splice(1, 2); // 删除 2 和 3
console.log(arr); // [1, 4, 5]
console.log(removed); // [2, 3]
splice 的强大在于可组合性,因为除了删除,还可以在同一调用中插入新元素,甚至进行替换操作。
2.2 插入和替换
除了删除,splice 还可以在指定位置插入新元素,或在删除的同时替换为新值。这使得 splice 在就地修改数组时非常高效。
const arr = [1, 2, 3, 4, 5];
arr.splice(2, 0, 'a', 'b'); // 在索引 2 处插入 'a' 和 'b'
console.log(arr); // [1, 2, 'a', 'b', 3, 4, 5]
3. slice 与 splice 的区别与适用场景
3.1 关键差异
在本质上,slice 不修改原数组、返回一个新数组,而 splice 会修改原数组并返回删除的元素组成的新数组。这个差异决定了两者在语义上的定位:slice 适合“只读获取子集”,splice 适合“就地修改数组”。
理解这一点对复杂数据处理尤为重要:如果你需要保持原数据不变,优先使用 slice;如果你需要在原地更新数据结构,使用 splice。
const a = [1, 2, 3, 4, 5];
const b = a.slice(1, 4); // [2, 3, 4], a 未变
const c = (function(){ a.splice(1, 2); return a; })(); // a 变为 [1, 4, 5]
3.2 适用场景要点
具体场景中,slice 适用于数据不可变的子集获取、分离数据流,以及需要将子集传递给下游函数的场景。splice 适用于就地删除、插入、替换数组元素,尤其在对大数组进行多次结构性修改时。
4. 性能对比及要点
4.1 性能基本概念
从实现角度看,slice 需要复制被返回子数组的元素,因此时间复杂度与截取长度成正比,且产生新数组的内存开销与被复制的元素数量相关。
相比之下,splice 由于要修改原数组结构、移动后续元素,除了删除的元素,可能还涉及大量的内存移动和引用调整,因此在大数组上会有显著的性能成本,且会改变原数组的长度。
// 简单性能对比示意(仅作示例,实际性能依赖引擎实现和硬件)
const arr = Array.from({length: 100000}, (_,i)=>i);
console.time('slice');
const sub = arr.slice(50000, 60000);
console.timeEnd('slice'); // 线性与截取长度相关
console.time('splice');
arr.splice(50000, 10000);
console.timeEnd('splice'); // 修改原数组,成本包含移动
在实际开发中,若追求不可变数据流,优先使用 slice,并在需要时通过组合操作得到新数组。若需要就地修改,才考虑 splice,并尽量减少修改量以降低性能开销。
5. 常见陷阱与用法误区
5.1 常见误区
请注意,slice 拷贝的是对元素的引用;若数组中的元素是对象,拷贝的是对象引用,修改对象属性会影响原数组中的对象,因此需要区分浅拷贝与深拷贝的需求。
splice 会导致原数组结构变化,若在遍历中使用 splice,可能引发索引错位或跳过元素的问题,建议在遍历前规划好修改策略或使用缓冲区。
负数索引的处理要点也常被忽略:slice 和 splice 的起始和结束边界都支持负数,表示从数组末尾计数。


