0%

JS 輕鬆淺拷貝的陣列 Array 方法 slice()

Day 20

老闆,幫我切一段香腸,從第三節到第六節,你手握著的那節不要。謝謝!

slice 的英文是切片或擷取,我們生活中常用的像是:「slice of life」生活的小片段、「slice of bread」一片麵包都是在表示一部分或「片狀」。但在陣列使用slice()的情境,比較像是「切  一段」,因為可以指定從某個元素切到某一個元素 的前一個。 切下來的部份是以複製的型態產生,所以也不會影響原本的陣列。

要哪段給哪段的 slice()

Array.prototype.slice() | MDN

原型: Array.prototype.slice()
功能: 回傳一個新陣列物件,為原陣列選擇的 begin 至 end(不含 end)部分的淺拷貝(shallow copy)。
改變: 原本的陣列將不會被修改。
語法: arr.slice([begin[, end]])
回傳值: 傳新陣列
參數: begin 自此索引(起始為 0)開始提取拷貝。 end 至此索引值之前停止提取

slice()有兩個預設參數,第一個參數是要從哪個索引值開始切,第二個參數是要在哪一個索引值結束,第二個參數常會讓人會錯意,因為第二個參數如果是三,slice()其實只會取到索引值為二就停止。比較好記的方法是把第二個參數減一,那會比較符合我們平常對「從這裡切到那裡」的認知。

https://ithelp.ithome.com.tw/upload/images/20191005/20104175upSsl1vmpz.png

只給一個參數的時候

不給參數就什麼都給你

在使用slice()的時候,如果不給參數,或只給零,那麼slice()就會把陣列從頭到尾複製一份給我們,也因此,許多人拿slice()來做陣列的淺拷貝,簡潔又方便。 就淺淺的拷貝喔

1
2
3
4
5
6
const colors1 = ['red', 'yellow', 'blue', 'gray', 'purple'];
const colors2 = colors1.slice();
const colors3 = colors1.slice(0);

colors2; // [ 'red', 'yellow', 'blue', 'gray', 'purple' ]
colors3; // [ 'red', 'yellow', 'blue', 'gray', 'purple' ]

給我負數我就倒立給你看

如果我們給的參數是負數,又會發生什麼事?就像length-1ㄧ樣,slice()會從陣列的尾端開始數,如果是-1,就會從陣列尾端取一個,如果這個負數超過陣列的長度,slice()就會把所有能給我們都給出來。

1
2
3
4
5
6
const colors1 = ['red', 'yellow', 'blue', 'gray', 'purple'];
const colors2 = colors1.slice(-1);
const colors3 = colors1.slice(-6);

colors2; // [ 'purple' ]
colors3; // [ 'red', 'yellow', 'blue', 'gray', 'purple' ]

我們可以發現,當我們參數是-1時,就好像是使用pop(),只是pop()回傳給我們的被刪掉值的索引值,但是slice(-1)卻會回傳陣列最後一個元素。

遇到多維的深拷貝就失效

雖然拿slice()來複製陣列很方便,但如果遇到多維陣列,slice()的複製就會失效。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 多維陣列,slice() 深拷貝失效
const arr1 = [
[1, 2, 3],
[4, 5, 6]
];
const arr2 = arr1.slice(0);

arr2; // [ [ 1, 2, 3 ], [ 4, 5, 6 ] ]

// 修改原陣列
arr1[0][0] = 'Hi';

// 兩個陣列都被修改了
arr1; // [ [ 'Hi', 2, 3 ], [ 4, 5, 6 ] ]
arr2; // [ [ 'Hi', 2, 3 ], [ 4, 5, 6 ] ]

兩個參數給好給滿

slice()的第二個參數頗曖昧我們都知道,明明是要擷取至索引值 4 卻只會擷取到 3,在記slice()第二個參數的時候,只要把刪除的索引值再 +1 會比較好記 或是相反
我們來看有第二個參數時的變化:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
const friends1 = ['Ayda', 'Phi', 'Alex', 'Chris', 'Tracy', 'Thomas', 'Jean'];

// 從索引值 1 擷取 至 2 (2+1=3)
const friends2 = friends1.slice(1, 3);
friends2; // [ 'Phi', 'Alex' ]

// 只要第二個參數是 0 就會回傳空陣列
const friends3 = friends1.slice(1, 0);
friends3; // []

// -2 是從尾端開始數回來
const friends4 = friends1.slice(2, -2);
friends4; // [ 'Alex', 'Chris', 'Tracy' ]

const friends5 = friends1.slice(2, 2);
friends5; // []

如果第二個參數是負數,表示從陣列的尾端算回來。
如果第二個參數比原陣列的長度長,那麼slice()就會擷取到陣列的最後一個元素。
如果第二個參數和第一個參數一樣,slice()會回傳空陣列,因為第二個參數會 -1 也就把第一個參數給減掉了。

slice()雖然是簡單的陣列方法,但是如果能夠靈活運用,相信對陣列的操控會更加方便。

這邊有篇以可愛的土司做示範的slice()介紹文,也很直得參考喔~
Arrays, any way you slice it

如有需要改進的地方,拜託懇求請告知,我會盡量快速度修改,感謝您~