JavaScript数组切片方法

2,663 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第20天,点击查看活动详情

数组上的slice方法返回数组一部分的浅拷贝。它需要两个数字, astart和 an end。每个数组都有一个slice方法。这是一个简单的例子:

let myArray = [ '⚡️', '🔎', '🔑', '🔩' ];
let newArray = myArray.slice(2, 3);

console.log(newArray); // [ '🔑' ]

slice该方法有两个可选参数start, 和end。如果您愿意,您可以同时提供两者、仅提供start或都不提供 - 所以所有这些都是有效的:

let arrayOne = [ '⚡️', '🔎', '🔑', '🔩' ];
let arrayOneSlice = arrayOne.slice(2, 3);  // [ '🔑' ]

let arrayTwo = [ '⚡️', '🔎', '🔑', '🔩' ];
let arrayTwoSlice = arrayTwo.slice(2);  // [ '🔑', '🔩' ]

let arrayThree = [ '⚡️', '🔎', '🔑', '🔩' ];
let arrayThreeSlice = arrayThree.slice();  // [ '⚡️', '🔎', '🔑', '🔩' ]

开始

这是要包含在新数组中的第一项的索引。例如,如果设置为2slice则将在索引 2 处开始新的数组副本。如果使用负数,则表示距序列末尾的偏移量。例如:

let arrayOne = [ '⚡️', '🔎', '🔑', '🔩' ];
let arrayOneSlice = arrayOne.slice(-2);  // [ '🔑', '🔩' ]
let arrayOneSliceAgain = arrayOne.slice(-1);  // [ '🔩' ]

结尾

这是从切片数组中排除的第一个元素- 这有点令人困惑。您可能希望end表示要包含的最后一项 - 但它是要排除的第一项。如果你使用,请记住这一点slice!如果省略此参数,则该slice方法将简单地继续到数组的末尾,如下例所示:

let arrayTwo = [ '⚡️', '🔎', '🔑', '🔩' ];
let arrayTwoSlice = myArray.slice(2);  // [ '🔑', '🔩' ]

如果使用了大于数组长度的值,slice则只延续到数组的末尾。如果使用负值,则表示距数组末尾的偏移量。例如,(2, -1)将从数组的开头开始为 2,从数组的结尾开始为 -1:

let arrayOne = [ '⚡️', '🔎', '🔑', '🔩' ];
let arrayOneSlice = arrayOne.slice(2, -1);  // [ '🔑' ]
let arrayOneSliceAgain = arrayOne.slice(1, -1);  // [ '🔎', '🔑' ]

使用切片制作数组的副本

Slice不会改变原始数组。相反,它会创建一个新的浅拷贝。因此,您现有的数组仍将继续包含相同的值:

let arrayOne = [ '⚡️', '🔎', '🔑', '🔩' ];
let arrayOneSlice = arrayOne.slice(2, 3);  

console.log(arrayOne); // [ '⚡️', '🔎', '🔑', '🔩' ]
console.log(arrayOneSlice); // [ '🔑' ]

由于slice制作了数组的浅拷贝,它有时也用于复制和制作数组数据的副本。例如,一个空slice函数也会在内存中创建一个新数组 - 允许您在内存中拥有相同数组的两个副本且具有相同的引用:

let arrayOne = [ '⚡️', '🔎', '🔑', '🔩' ];
let arrayOneSlice = arrayOne.slice();

arrayOneSlice[2] = '⚡️'
console.log(arrayOne); // [ '⚡️', '🔎', '🔑', '🔩' ]
console.log(arrayOneSlice); // [ '⚡️', '🔎', '⚡️', '🔩' ]

这在某些情况下可能很有用。但是,slice只制作数组的浅拷贝。这意味着当您的数组中有对象时,事情会变得有些混乱。考虑以下数组:

let arrayOne = [ { items: [ '⚡️', '🔎', '🔑', '🔩' ]}, '👨‍💻', '😄', '🐔' ]

该数组中包含一个对象。让我们尝试制作这个数组的切片副本,然后更新items

let arrayOne = [ { items: [ '⚡️', '🔎', '🔑', '🔩' ]}, '👨‍💻', '😄', '🐔' ]
let arrayOneSlice = arrayOne.slice(0, 2);

arrayOneSlice[0].items = [ '🔎' ];
arrayOneSlice[1] = '🔎';

console.log(arrayOne); // [ { items: [ '🔎' ]}, '👨‍💻', '😄', '🐔' ]
console.log(arrayOneSlice); // [ { items: [ '🔎' ]}, '🔎' ]

等等,什么?我们更改了arrayOneSlice'items对象,但它在arrayOne和中都发生了变化arrayOneSlice!与此同时,arrayOneSlice[1]只是变了arrayOneSlice!欢迎来到另一个 Javascript 怪癖。在第一个示例中,使用arrayOneSlice[0].items符号,Javascript 将其解释为更新浅副本中的现有元素,因此它会影响原始元素。然而,有点令人困惑的是,通过使用该arrayOneSlice[1]符号,Javascript 将其解释为将一个新值放入[1]浅拷贝本身的位置。

这意味着,尽管在使用简单数组时看起来像是在制作副本,但在更复杂的对象上使用它时却不成立。知道这一点小事有一天会为你节省很多时间。slice

结论

JavaScript slice方法对于使用原始数组数据的子集创建新的数组浅拷贝非常有用。它还可以以有限的方式用于制作可以独立更新的副本。JavaScript slice仍然与内存中的原始副本具有相同的引用,这在操作它们时很有用。