在js中,經常要對陣列進行拷貝操作,但如果只是簡單的將它賦予其他變數,那麼之後只需要修改乙個變數,其他的就都會受到影響一起改變。這便是陣列的深淺拷貝問題,像這種直接賦值的方式就是淺拷貝,但很多時候,這樣並不是我們想要得到的結果。
舉個例子:
var arr1 = [0,1,2,3];var arr2 =arr1;
arr2[1] = "hello";
console.log(arr1);
//[0,'hello',2,3]
由上可知,修改了 arr2 之後,arr1 也隨之改變了。同樣,在js中物件的拷貝操作也是如此。
var obj1 =var obj2 =obj1;
obj2.color = 'red';
console.log(obj1.color);
//'red'
1. 深淺拷貝
js大致分成兩種資料型別:基本資料型別和引用資料型別。
基本資料型別儲存在棧記憶體,而引用型別則儲存在堆記憶體中。對於基本資料型別的拷貝,並沒有深淺拷貝的區別,我們所說的深淺拷貝都是對於引用資料型別而言的。
淺拷貝:淺拷貝是複製引用,複製後的引用都是指向同乙個物件的例項,彼此之間的操作會互相影響。
深拷貝:深拷貝不是簡單的複製引用,而是在堆中重新分配記憶體,並且把源物件例項的所有屬性都進行新建複製,以保證深拷貝的物件的引用圖不包含任何原有物件或物件圖上的任何物件,複製後的物件與原來的物件是完全隔離的。
2. 淺拷貝的實現
像上面兩個例子這樣的直接複製引用方式便是淺拷貝。
3. 深拷貝的實現
a、array的slice和concat方法
var arr1 = [0,1,2,3];var arr2 =arr1;
var arr3 =arr1.slice();
var arr4 =arr1.concat();
arr3[1] = "hello";
arr4[1] = "world";
console.log(arr1);
//[0,1,2,3]
console.log(arr3); //
[0,'hello',2,3]
console.log(arr4); //
[0,'world',2,3]
console.log(arr1 == arr2); //
true
console.log(arr1 == arr3); //
false
console.log(arr1 == arr4); //
false
由上面的**可知,array的slice和concat方法都會返回乙個新的陣列例項,並且自己的操作不會影響到其他物件。但如果陣列是多層的話,情況就會不同了。
var arr1 = [0,[1,1,1,1],2,3,];var arr2 =arr1;
var arr3 =arr1.slice();
var arr4 =arr1.concat();
arr3[1][1] = "0";
arr4[4].name = "red";
console.log(arr1)
//[0,[1,0,1,1],2,3,]
console.log(arr2) //
[0,[1,0,1,1],2,3,]
console.log(arr3) //
[0,[1,0,1,1],2,3,]
console.log(arr4) //
[0,[1,0,1,1],2,3,]
如果像上面的例子,陣列是多層的,那麼slice和concat方法只能對第一層進行深拷貝。
b、json物件的parse和stringify
json物件的parse方法可以將json字串反序列化成js物件,stringify方法可以將js物件序列化成json字串。
var obj1 =,number: [1,1,1,1]
};var obj2 =json.parse(json.stringify(obj1));
console.log(obj1 == obj2); //
false
obj2.name = "father_change";
obj2.child.name = "son_change";
obj2.number[1] = 0;
console.log(obj1);
//, number: [1,1,1,1]}
console.log(obj2); //
, number: [1,0,1,1]}
由上例子可知,拷貝之後的obj2和obj1也是相互隔離的,借助這兩個方法,也可以實現物件的深拷貝。但是如果物件中包含乙個函式,就會出現一些問題。
var obj3 =};var obj4 =json.parse(json.stringify(obj3));
console.log(obj3);
//
如上情況,obj3中包含乙個函式say,拷貝後的obj4中並沒有找到say函式。所以說如果物件中含有乙個函式時,就不能用這個方法進行深拷貝。
c、遞迴拷貝
遞迴拷貝就是對每一層的資料都實現一次 建立物件->物件賦值 的操作,**如下:
functiondeepclone(obj); //
判斷複製的目標是陣列還是物件
for(let i in
obj)
else
}}
return
objclone;
}var obj1 =,
number: [1,1,1,1],
say:
function
()};
var obj2 =deepclone(obj1);
console.log(obj1 == obj2); //
false
obj2.name = "father_change";
obj2.child.name = "son_change";
obj2.number[1] = 0;
console.log(obj1);
//, number: [1,1,1,1], say: f()}
console.log(obj2); //
, number: [1,0,1,1], say: f()}
可以看到,obj2在通過遞迴拷貝之後,也可以實現與obj1的相互隔離,所以說遞迴拷貝也是一種深拷貝方式。並且,使用遞迴方法進行拷貝不會忽視物件中的函式,所以使用遞迴方法可以實現完全意義上的深拷貝。
綜上:
slice和concat方法只能進行第一層的深拷貝(如果只想對一些簡單基本的物件進行深拷貝,用這兩個方法即可);
json.parse和json.stringify能實現深拷貝,但會忽視物件中的函式(如果想對多層的但不含有函式的物件進行深拷貝,可用此方法);
遞迴方法則可以實現真正意義上的深拷貝。
JS深 淺拷貝
在js中,資料型別分為基本資料型別和引用資料型別兩種。對於基本資料型別來說,它的值直接儲存在棧記憶體中,而對於引用型別來說,它在棧記憶體中只是儲存了乙個指向對記憶體的引用,而真正的資料儲存在堆記憶體中。object array 這兩個就是引用型別,當我門直接去拷貝的話 copyobj obj 拷貝的...
js 深淺拷貝
深拷貝就是複製內部內容 淺拷貝就是複製記憶體位址 var obj 淺拷貝 引用傳遞 淺拷貝就是賦值,將鑰匙複製乙份 var o obj 深拷貝 內部內容複製乙份 將房子複製乙份 方法一 var str json stringify obj var obj3 json parse str 方法二 va...
js深淺拷貝
1.什麼是深淺拷貝 簡單的來說,加入b複製a a改變 如果b也跟著改變的話,那就是淺拷貝,反之是深拷貝 實現淺拷貝方法 1.賦值操作 var a 0 1,2 3,4 var b a a 0 5console log a 5,1,2,3,4 console log b 5,1,2,3,4 2.es6 ...