一、什麼是深拷貝
在JS中,對象是通過引用傳遞的。當我們將一個對象賦值給另一個變數時,實際上是將對象的指針(引用地址)賦值給該變數,而非複製對象的內容。這意味著,當我們更改新變數的屬性時,原始變數的屬性也會被更改。
當我們需要複製一個對象,並確保修改副本不會對原始對象造成任何影響時,需要對對象進行深拷貝。深拷貝將克隆一個全新的對象,而不是指針地址。
二、淺拷貝的問題
我們先來看一個簡單的例子:
let obj1 = { a: 1, b: { c: 2, }, }; let obj2 = obj1; obj1.a = 10; obj2.b.c = 20; console.log(obj1); console.log(obj2);
在這個例子中,我們通過賦值的方式創建了一個對象副本。我們發現,對obj2的修改也會影響到obj1,因為它們指向同一個對象。這就是淺拷貝的問題。
使用深拷貝可以解決這個問題。
三、常見的深拷貝方法
1. JSON.parse(JSON.stringify(object))
這是使用JSON的方法。我們先將對象序列化為JSON格式的字元串,然後再將其解析為新對象。這種方法可以很好地複製簡單對象,並且很容易實現:
let obj1 = { a: 1, b: { c: 2, }, }; let obj2 = JSON.parse(JSON.stringify(obj1)); obj1.a = 10; obj2.b.c = 20; console.log(obj1); console.log(obj2);
這種方法很簡單,可是如果對象中包含函數、日期、正則表達式等特殊類型的數據,會出現意料之外的結果。例如:
let obj1 = { a: 1, b: function() {console.log('a');}, c: new Date(), d: /123/, }; let obj2 = JSON.parse(JSON.stringify(obj1)); console.log(obj1); console.log(obj2);
這段代碼將拋出錯誤,因為函數無法被序列化。
2. 遞歸複製對象
另一種方式是遞歸複製對象。我們首先創建一個新對象,然後遍歷原始對象並遞歸複製其屬性:
function deepCopy(obj) { let newObj = Array.isArray(obj) ? [] : {}; if (obj && typeof obj === "object") { for (let key in obj) { if (obj.hasOwnProperty(key)) { newObj[key] = deepCopy(obj[key]); } } } return newObj; } let obj1 = { a: 1, b: { c: 2, }, }; let obj2 = deepCopy(obj1); obj1.a = 10; obj2.b.c = 20; console.log(obj1); console.log(obj2);
這種方法可以正確地複製對象和函數,並且能夠處理循環引用,但是效率低下。
3. 使用第三方庫
最後一種方式是使用第三方庫,比如Lodash的深拷貝方法:
let obj1 = { a: 1, b: { c: 2, }, }; let obj2 = _.cloneDeep(obj1); obj1.a = 10; obj2.b.c = 20; console.log(obj1); console.log(obj2);
這種方法使用起來非常簡單,而且可以處理各種情況。但是需要引入第三方庫,增加了項目的依賴。
四、總結
深拷貝是保證對象副本獨立於原始對象的必要手段。在選擇深拷貝方法時,可以根據實際情況選擇不同的方案。JSON.parse(JSON.stringify(object))可以簡單地處理大多數簡單對象,但是不支持函數、日期、正則表達式等類型。
遞歸複製對象可以處理各種類型的對象,但是效率較低。
使用第三方庫可以處理各種情況,但是需要引入依賴。
原創文章,作者:NBAPS,如若轉載,請註明出處:https://www.506064.com/zh-tw/n/332918.html