JavaScript深拷貝和淺拷貝

wade3po發表於2019-01-23

在JavaScript中運算元據的時候,基礎資料型別還好,不管是我們怎麼賦值修改都不會有什麼問題,但是如果我們操作的是陣列或者Object,那很容易出現修改了一個值就會把所有的都給變了,這就是淺拷貝。

var obj1 = {a: 10};
var obj2 = obj1;
obj2.a = 40;
console.log(obj1);// {a: 40}
console.log(obj2);// {a: 40}

 

var arr1 = [0];
var arr2 = arr1;
arr2[0] = 5;
console.log(arr1);
console.log(arr2);
複製程式碼

我們明明想只是修改物件或者陣列中的另一個,為什麼兩個都改變了。這就涉及深拷貝和淺拷貝了。

淺拷貝:只複製指向某個物件的指標,而不復制物件本身,新舊物件共享一塊記憶體; 深拷貝:複製並建立一個一摸一樣的物件,不共享記憶體,修改新物件,舊物件保持不變。

這原理其實跟堆記憶體、棧記憶體、指標有關係,在這邊就不講了。

那怎麼能深拷貝呢?方法很多,比如Object的assign、迴圈賦值新的一個物件、jQuery的extend方法等等,但是這些都複雜化了,雖然可以實現但本人不推薦。

如果是陣列,那麼我們用slice和concat函式,這兩個函式都會返回一個新的陣列,而引數只要不設定,返回的就是原本的陣列。

var arr1 = [0];
var arr2 = arr1.slice(0);
arr2[0] = 5;
console.log(arr1);
console.log(arr2);

 

 

var arr1 = [0];
var arr2 = arr1.concat();
arr2[0] = 5;
console.log(arr1);
console.log(arr2);
複製程式碼

輸出的都是原來陣列的。在我認為,這兩個方法是最簡單的陣列深拷貝方法,當然也可以迴圈賦值一個新的陣列,跟下面物件一樣。

如果是物件,那我推薦轉成字串然後再轉回物件。

var obj1 = {a: 10};
var obj2 = JSON.parse(JSON.stringify(obj1));
obj2.a = 40;
console.log(obj1);
console.log(obj2);
複製程式碼

但是,如果物件裡面是函式的話,這個方法是沒辦法把函式賦值的。

var obj1 = {a: 10, b:function () {
        alert(5);
    }};
var obj2 = JSON.parse(JSON.stringify(obj1));
obj2.a = 40;
console.log(obj1.b);
console.log(obj2.b);
複製程式碼

Obj2.b輸出undefined,沒辦法拷貝函式。所以物件中如果有涉及函式,一般用迴圈賦值進行深拷貝。

var obj1 = {a: 10, b:function () {
        alert(5);
    }};
var obj2 = {}
for(var i in obj1) {
    obj2[i] = obj1[i];
};
console.log(obj1);
console.log(obj2.b);
複製程式碼

不僅函式可以拷貝,在修改任何一個物件的時候不會把另一個給修改了。

如果有什麼指教請留言,或者有什麼問題也請留言,我們會盡我們最大努力幫您解答。

歡迎關注Coding個人筆記 公眾號

相關文章