在处理数组数据时,截取某一段元素是再常见不过的需求,比如分页展示列表、提取前几条记录、复制整个数组等。JavaScript 提供的 slice 方法正是为这类需求设计的,它不会改动原数组,而是返回一个浅拷贝的新数组。理解它的参数规则和边界行为,是用好这个方法的关键。

slice 方法的基本语法与参数规则
slice的语法为 array.slice(start, end),其中 start 表示截取的起始索引,end 表示截取的结束索引(不包含该位置)。两个参数都可以省略,返回结果遵循以下规则。
当只传一个参数时,slice 会从该索引开始一直截取到数组末尾。例如 [1,2,3,4,5].slice(2) 返回 [3,4,5],索引为 2 的元素是 3,从它开始到结尾全部取出。当两个参数都不传时,返回一个与原数组内容完全相同的新数组,这也是复制数组最常用的写法之一。
const arr = [10, 20, 30, 40, 50]; // 从索引1开始截取到索引3(不包含3) console.log(arr.slice(1, 3)); // [20, 30] // 只传起始索引,截取到末尾 console.log(arr.slice(2)); // [30, 40, 50] // 不传参数,复制整个数组 const copy = arr.slice(); console.log(copy); // [10, 20, 30, 40, 50] // 原数组不受影响 console.log(arr); // [10, 20, 30, 40, 50]
需要注意的一点是,end 对应的元素不会被包含在结果里,这是很多人的记忆误区。记住口诀“含头不含尾”,即结果包含 start 位置的元素,但不包含 end 位置的元素。所以 slice(1, 3) 实际取出的是索引 1 和索引 2 两个元素。
负数索引的妙用
slice 的两个参数都支持负数,负数表示从数组末尾往前数的位置。-1 代表最后一个元素,-2 代表倒数第二个,以此类推。这个特性在取数组尾部数据时特别方便。
换算规则是:实际索引 = 数组长度 + 负数值。例如长度为 5 的数组传入 -2,实际索引就是 3。如果换算后的起始索引大于结束索引,slice 不会报错,而是返回空数组,这一点比很多严格抛异常的方法要宽容得多。
const list = ['a', 'b', 'c', 'd', 'e']; // 取最后两个元素 console.log(list.slice(-2)); // ['d', 'e'] // 从倒数第三个取到倒数第一个(不含最后那个) console.log(list.slice(-3, -1)); // ['c', 'd'] // 起始位置在结束位置之后,返回空数组 console.log(list.slice(3, 1)); // [] // 索引越界会自动被规范化处理 console.log(list.slice(1, 100)); // ['b', 'c', 'd', 'e'] console.log(list.slice(-100, 2)); // ['a', 'b']
从上面的例子还能看到 slice 对越界参数的处理:结束索引超出数组长度时按数组末尾处理,起始索引换算后小于 0 时按 0 处理。这种自动纠错机制让代码不需要额外写边界判断,但也要留意它可能掩盖逻辑错误,参数传错时程序不会报错而是给出“合理”的结果,排查问题时需要多留心。
slice 与 splice 的区别
这两个方法名字只差一个字母,行为却完全不同,是面试和实际开发中高频出现的混淆点。最核心的区别是:slice 不修改原数组,只返回新数组;splice 会直接修改原数组,可以用来删除、插入或替换元素。
const a = [1, 2, 3, 4, 5]; const b = [1, 2, 3, 4, 5]; // slice:原数组不变 const result1 = a.slice(1, 3); console.log(result1); // [2, 3] console.log(a); // [1, 2, 3, 4, 5] 原数组完好 // splice:直接删掉原数组的元素 const result2 = b.splice(1, 3); console.log(result2); // [2, 3, 4] 被删除的部分 console.log(b); // [1, 5] 原数组被改变了
第二个参数的含义也不一样。slice(start, end) 的第二个参数是结束索引;splice(start, deleteCount) 的第二个参数是要删除的元素个数。同样是 (1, 3),slice 取出两个元素,splice 删掉三个元素。在函数式编程或者需要保持数据不可变的场景下,优先使用 slice;确需原地修改数组时才用 splice。
实际开发中的典型用法
除了基本的截取操作,slice 在实际项目里还有几个非常实用的应用场景。掌握它们能让代码更简洁。
第一个场景是把类数组对象转换为真正的数组。函数内部的 arguments、DOM 查询返回的 NodeList 都是类数组,它们没有 map、filter 这些方法,通过 Array.prototype.slice.call() 可以快速转换:
function sum() {
// arguments 是类数组,先转成数组再使用 reduce
const nums = Array.prototype.slice.call(arguments);
return nums.reduce((a, b) => a + b, 0);
}
console.log(sum(1, 2, 3, 4)); // 10第二个场景是分页展示。假设每页显示 10 条数据,当前是第 3 页,直接用 data.slice((3 - 1) * 10, 3 * 10) 就能拿到该页的数据,写法直观且不影响原始数据源。
const allItems = Array.from({ length: 35 }, (_, i) => i + 1);
function getPageData(data, page, pageSize) {
return data.slice((page - 1) * pageSize, page * pageSize);
}
console.log(getPageData(allItems, 3, 10)); // [21,22,23,24,25,26,27,28,29,30]
console.log(getPageData(allItems, 4, 10)); // [31,32,33,34,35] 不足一页自动截断第三个要留意的点是浅拷贝特性。slice 只复制数组的第一层,如果数组元素是对象,新旧数组中的对象仍然指向同一个引用,修改其中一个会影响另一个。需要完全隔离时,得配合 JSON.parse(JSON.stringify()) 或者递归拷贝、structuredClone 等深拷贝方案。
const users = [{ name: '张三' }, { name: '李四' }];
const usersCopy = users.slice();
usersCopy[0].name = '王五';
console.log(users[0].name); // '王五' 被连带修改了,因为是浅拷贝另外,字符串也有同名方法 String.prototype.slice,参数规则与数组版本完全一致,同样支持负数索引,可以用来截取字符串片段。而 substring 不支持负数且会自动交换大小参数,substr 已被标记为废弃,建议统一使用 slice 保持一致性。
js slice数组截取JavaScript数组修改时间:2026-09-15 22:30:41