J 筆記 - Deep Clone Array
之前有介紹過如何 Clone an Array,但可以知道的問題是,如果今天是 Array 裡面又有更深層的 Array 的話(Deep Array),再複製陣列上就會有點問題,也如同上篇的 Only one level 的結論。因此,這篇就來介紹兩種 Deep Clone Array 的方法吧!
1 2 3 4 5 6 7 8 9 10 11
| const nestedArray = ['ES5', ['ES6', ['ES7']], ['ES8']];
JSON.parse(JSON.stringify(nestedArray));
_.cloneDeep(nestedArray);
const clone = (items) => items.map(item => Array.isArray(item) ? clone(item) : item); clone(nestedArray);
|
Copying a Value type
先來個最基本的數組,這部分應該很好理解,宣告一個 value
。而且如果我們更改 valueCopy
,不會影響原本的 value
。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| let value = 9527; let cloneValue = value;
console.log(cloneValue);
cloneValue = 100;
console.log(cloneValue);
console.log(value);
|
Copying a Reference type
如果上篇所述,為什麼原始陣列也會受到影響?那是因為複製的不是數組本身,而是指向數組的記憶體位址。
1 2 3 4 5 6 7 8 9 10 11
| const initarray = ['ES5', 'ES6', 'ES7'];
const initarray2 = initarray;
initarray2.push('❌');
console.log(initarray2);
console.log(initarray);
|
因此,有了上篇的解決方案:
1 2 3 4 5 6 7 8 9 10 11
| const initarray = ['ES5', 'ES6', 'ES7'];
const initarray2 = [...initarray];
initarray2.push('✔️');
console.log(initarray2);
console.log(initarray);
|
Deep Clone
知道了上面的方法後,讓我們現在來看看透過 Spread ...
與 Array.from
雖然可以複製陣列,但只能複製 Only one level 的問題,而無法解決巢狀亦又或者是 Deep Clone
。
可以發現,原本的 nestedArray
的陣列一並沒有改變 ES5
,這很符合我們上邊敘述複製 Only one Level 的方法,不過後面的 ES6
就被改為 Deep!!!
了!
1 2 3 4 5 6 7 8 9 10
| const nestedArray = ['ES5', ['ES6', ['ES7']], ['ES8']]; const copynestedArray = [...nestedArray];
copynestedArray[0] = 'ES0'; copynestedArray[1][0] = 'Deep!!!'; console.log(copynestedArray);
console.log(nestedArray);
|
JSON & Recursion & lodash
接下來,我們來看看透過 JSON
的實作結果,如果有興趣看 lodash
的方法也可以去官網查看,這是一套滿多人在使用,可以更簡潔寫 code 的 js 套件。
https://lodash.com/docs/
1 2 3 4 5 6 7 8 9 10
| const nestedArray = ['ES5', ['ES6', ['ES7']], ['ES8']]; let JSONcopynestedArray = JSON.parse(JSON.stringify(nestedArray));
JSONcopynestedArray[0] = 'ES0'; JSONcopynestedArray[1][0] = 'Deep!!!'; console.log(JSONcopynestedArray);
console.log(nestedArray);
|
另外,也可以使用 Recursion 遞迴
來完成複製
1 2 3 4 5 6 7 8 9 10 11 12
| const clone = (items) => items.map(item => Array.isArray(item) ? clone(item) : item);
const nestedArray = ['ES5', ['ES6', ['ES7']], ['ES8']]; var RecursionArray = clone(nestedArray)
RecursionArray[0] = 'ES0'; RecursionArray[1][0] = 'Deep!!!'; console.log(RecursionArray);
console.log(nestedArray);
|
Values Not Compatible with JSON
Note!!! 值得注意的是,如果數值與 JSON 不兼容,轉譯的時候會出現錯誤
1 2 3 4 5 6
| function copynestedArray(array) { return JSON.parse(JSON.stringify(array)); }
copynestedArray([1, undefined, 2]) copynestedArray([document.body, document.querySelector('p')])
|
參考資料