本文檔適用于有一定經驗的開發者。我們默認你已經掌握了指針的概念(也可稱為地址) ,如果你是新手,你可能需要先了解 指針的概念
我們在JS中經常需要復制一個對象或數組。
當我們直接使用
=賦值時
,我們實際只賦值了這個對象的指針。這種情況 連拷貝都算不上。
例:如下我們給array2賦值,實際是賦值給array2一個指針,指針指向array1指向的數組。因此我們編輯 array2 時,array1也會變。
let array1 = [1,2,3]
let array2 = array1
array2[0] = 100
/*
array1
>(3) [100, 2, 3]
array2
(3) [100, 2, 3]
*/
淺拷貝可以將數組(對象)的第一層拷貝下來。
ES6給我們提供了兩個方便的淺拷貝方法:
Array.from()與Object.assign()
例:下面我們通過Array.from()
對array3進行淺拷貝。我們可以看出,當我們修改array4的普通元素時,array3已經不會隨著改變了。但是淺拷貝只是拷貝了第一層的元素,如果第一層元素含有對象(數組),我們只拷貝一個指針(地址)。array4通過這個指針(地址)訪問的對象將是與array3是相同的。
let array3 = [1,2,3,{a:1,b:2,c:3}]
let array4 = Array.from(array3)
array4[0] = 100
array4[3].a = 100
/*
array3
>(4) [1, 2, 3, {a: 100, b: 2, c: 3}]
array4
>(4) [100, 2, 3, {a: 100, b: 2, c: 3}]
*/
目前JS常見的深拷貝有兩種方式
。第一種種是兩次JSON化:
let array6 = JSON.parse(JSON.stringfiy(array5))
這種方法很簡單,但是當元素含有undefined
或正則表達式
時函數會拋出異常。
第二種深拷貝是逐層遍歷逐一賦值的方法,要麻煩一些,但是沒有第一種的缺點。
目前,這兩種以外的拷貝方式都是淺拷貝。例如for...of遍歷中的item實際是對對象元素的淺拷貝。
// 例:逐層遍歷逐一賦值的深拷貝工具類
class deepCopy {
static toRawType(value) {
return Object.prototype.toString.call(value).slice(8, -1);
}
/* 已整合在tools中 */
static copy(obj) {
let emptyObject = null;
if (this.toRawType(obj) == 'Object') {
emptyObject = {};
}
else if (this.toRawType(obj) == 'Array') {
emptyObject = [];
}
else {
return obj;
}
for (let key in obj) {
if (typeof obj[key] != 'object' || obj[key] == null) {
emptyObject[key] = obj[key];
}
else {
emptyObject[key] = this.copy(obj[key]);
}
}
return emptyObject;
}
}
let array5 = [1,2,3,{a:1,b:2,c:3}]
let array6 = deepCopy.copy(array5)
array6[3].a = 100
/*
array3
>(4) [1, 2, 3, {a: 1, b: 2, c: 3}]
array4
>(4) [1, 2, 3, {a: 100, b: 2, c: 3}]
*/