天天看點

深複制和淺複制的原理

對于字元串類型,淺複制是對值的複制,對于對象來說,淺複制是對對象位址的複制,并沒 有開辟新的棧,也就是複制的結果是兩個對象指向同一個位址,修改其中一個對象的屬性,則另一個對象的屬性也會改變,而深複制則是開辟新的棧,兩個對象對應兩個不同的位址,修改一個對象的屬性,不會改變另一個對象的屬性。

下面分别介紹淺複制和深複制,首先講淺複制:

淺複制是複制引用,複制後的引用都是指向同一個對象的執行個體,彼此之間的操作會互相影響###

其實我們經常用到的複制都屬于淺複制,舉栗子:

var test={value:3};

var copTest=test;

copTest.value=7;

console.log(copTest);    //{ value: 7 }

console.log(test);          //{ value: 7 }

可以看到在上面我們複制後的 copyTest 修改值後,最初 test 的值也修改了,我們可以确定 var copTest=test 其實是将 test 對象所指向的位址賦給 copTest ,也就是說這步操作後 test 和 copTest 指向了同一塊記憶體位址,是以我們對 copTest.value 指派其實等同于對 test.value 進行指派。是以淺複制可以了解為隻複制了一個記憶體位址。

淺複制的好處就是可以有效的節約記憶體位址,避免不必要的記憶體浪費。

深複制就是複制執行個體,複制後的彼此之間的操作不會互相影響,但是實作深複制的方法可以有很多###

1.利用 Object.assign 方法實作深複制,assign用于對象的合并,将源對象( source )的所有可枚舉屬性,複制到目标對象( target ),Object.assign方法的第一個參數是目标對象,後面的參數都是源對象

直接看代碼:

let test = {a: 1, b: {c: 2}};

let newTest = Object.assign({}, test);

newTest.a = 2;

newTest.b.c = 3;

console.log(test.a);          //1

console.log(newTest.a);        //2

console.log(test.b.c);        //3

console.log(newTest.b.c);      //3

通過上面的代碼我們明白了深複制的意思,說透了就是先配置設定一個記憶體位址然後再指派,但是也注意到了, newTest.b.c=3 并沒有實作深複制,這是因為 Object.assign() 方法隻能深複制第一層的變量,是以第二層其實是一次淺複制。我們需要對 newTest.b 也用一次Object.assign()才能完成一次完整的深複制。如果 test 裡面有很多層,就要循環嵌套使用Object.assign()方法很多次。

2.JSON對象的parse和stringify

JSON對象parse方法可以将JSON字元串反序列化成JS對象,stringify方法可以将JS對象序列化成JSON字元串,借助這兩個方法,也可以實作對象的深複制。

var test1 = {name: "test1", child: {name: "child"}};

var test2 = JSON.parse(JSON.stringify(test1));

//改變target的name屬性

test2.name = "test2";

console.log(test1.name); //test1

console.log(test2.name); //test2

// 改變test2的child

test2.child.name = "test2 child";

console.log(test1.child.name); //child

console.log(test2.child.name); //test2 child

這樣的方法使用比較簡單,而且一次性就可以完全實作深複制。

但是這種方法也有不少壞處,譬如它會抛棄對象的constructor。也就是深拷貝之後,不管這個對象原來的構造函數是什麼,在深拷貝之後都會變成Object。

這種方法能正确處理的對象隻有Number, String, Boolean, Array, 扁平對象,即那些能夠被 json 直接表示的資料結構。RegExp對象是無法通過這種方式深拷貝。也就是說,隻有可以轉成JSON格式的對象才可以這樣用,像function沒辦法轉成JSON。

遞歸方法實作對象的深複制

深複制和淺複制的原理

數組的深copy:

對于數組我們可以使用slice() 和 concat() 方法來解決上面的問題

slice 
深複制和淺複制的原理
concat
深複制和淺複制的原理

知識點補充:

arrayObj.slice(start, [end]) 該方法傳回一個 Array 對象,其中包含了 arrayObj 的指定部分。不會改變原數組

arrayObj.concat() 方法用于連接配接兩個或多個數組。該方法不會改變現有的數組,而僅僅會傳回被連接配接數組的一個副本。

其實也就是下面這麼個意思。。。但還是用上面的方法來實作比較簡單高效些

深複制和淺複制的原理

參考文檔:

https://www.cnblogs.com/Chen-XiaoJun/p/6217373.html
上一篇: HTTP協定
下一篇: 連結清單

繼續閱讀