在 JavaScript 中深度克隆物件
JavaScript 是一種物件語言。幾乎所有內容都是 JavaScript 中的物件。布林值、數字、字串、日期、數學、Regex、陣列、函式和物件本身都是物件。它們是由各種屬性和方法組成的鍵值對的集合。它們直接儲存在記憶體中,並且只能通過引用進行復制。變數不儲存物件,而只是在記憶體中對該物件的引用。因此,當我們嘗試複製物件變數時,最終會建立對同一物件的額外引用。此方法稱為淺拷貝。這是不理想的,因為我們不希望更改原始物件來影響其克隆。這就需要一種方法來深度克隆物件。本教程講授如何在 JavaScript 中深度克隆物件。
淺拷貝與深拷貝
淺拷貝是物件的按位拷貝。建立的新物件成功複製了諸如數字、布林值和字串等基元,但未複製對物件的任何引用。只有引用地址會導致指向同一物件的指標。對原始物件所做的任何更改都會反映在淺拷貝中。
另一方面,深拷貝不僅將地址/引用複製到原始物件,還複製整個物件。建立的新物件與複製的物件沒有任何依賴關係。JavaScript 為我們提供了各種內建方法來複制物件,但是淺拷貝是大多數方法中的預設行為。
JavaScript 中的淺拷貝方法
我們將簡要介紹淺拷貝方法,以使你瞭解深拷貝的一些錯誤方法。
在 JavaScript 中使用 Spread
語法來淺拷貝物件
我們可以通過建立一個新物件來克隆物件,然後使用 Spread
語法將物件內部的內容列舉為物件本身。這似乎是正確的方法,但它會建立資料的淺拷貝。
const obj={
a: 1,
b: {
c: 2
}
}
const clone = {...obj}; // creates a shallow copy
obj.b.c =5;
console.log(clone.b.c); // outputs 5
在上面的程式碼中,我們使用 spread
語法建立物件的淺拷貝。然後,我們在原始物件中修改了引用物件的屬性之一,並表明在克隆的物件中該屬性已被修改。
在 JavaScript 中使用 Object.assign()
淺拷貝物件
object.assign()
方法將物件的淺拷貝分配給新的物件變數。它有兩個引數:target
和 source
。target
通常是一對空括號,用於表示要在其中複製的空物件。它是一個可選引數,但是傳遞它可以確保我們最終不會更改原始物件。第二個引數是要複製的物件。
const obj={
a: 1,
b: {
c: 2
}
}
const clone = Object.assign({},obj); // creates a shallow copy
obj.b.c =5;
console.log(clone.b.c); // outputs 5
在上面的程式碼中,我們使用 Object.assign()
建立物件的淺拷貝。然後,我們在原始物件中修改了引用物件的屬性之一,並表明在克隆的物件中該屬性已被修改。
JavaScript 中的深拷貝方法
在 JavaScript 中使用 JSON.parse()
和 JSON.stringify()
深度克隆物件
JSON.stringify()
用於將 JavaScript 物件轉換為 JSON 字串,JSON.parse()
用於將 JSON 字串轉換為 JavaScript 物件。我們可以將 JSON.parse()包裹在 JSON.stringify()周圍,以首先將 JavaScript 物件轉換為 JSON String,然後對其進行解析以獲得該物件的副本。
var user = { name: 'Harshit', age: 21, Profession: 'Software Engineer' };
let fakeDeepCopy = JSON.parse(JSON.stringify(user));
此方法建立深拷貝,但僅適用於沒有功能的物件。與其他引用物件一樣,它在任何迴圈依賴方面都有問題。複製物件中屬性的順序也可能與原始物件不同。因此,如果我們有一個簡單的物件而原始資料型別很少,那麼此方法是一個很好的技巧,但不建議在現實世界中使用。
在 JavaScript 中使用本機深度克隆深度克隆物件
我們可以使用 Node.js v8
模組的序列化演算法來深度克隆物件。儘管它僅限於某些內建資料型別,但它保留了克隆資料中的引用。它允許我們複製 JSON 方法不支援的幾個迴圈和遞迴結構。
const v8 = require('v8');
const structuredClone = obj => {
return v8.deserialize(v8.serialize(obj));
};
我們反序列化然後序列化物件,就像 JSON 方法的 stringify 和 parse 一樣。但是它保留了迴圈依賴關係,並且稍微好一些。
在 JavaScript 中使用 Lodash 庫深度克隆物件
Lodash 庫具有淺拷貝和深拷貝的函式,即 clone
和 clonedeep
。這是一個很棒的庫,它允許我們僅匯入所需的功能,而不匯入完整的庫。clonedeep
方法的工作方式是遞迴地複製值,然後保留所有物件繼承,從而建立物件的真實副本。
const lodashClonedeep = require('lodash.clonedeep');
let obj = {
a: 1,
b: {
c: 2
}
}
let deepClone = lodashClonedeep(obj);
在這裡,我們從 lodash 載入 clonedeep
函式,並使用它來深克隆物件。它是一個經過良好測試和維護的庫,但只能與 Node.js 一起使用,不能與 Vanilla JavaScript 一起使用。
在 JavaScript 中使用 jQuery extend()
方法深度克隆物件
我們可以使用 jQuery 的 .extend()
進行物件的淺拷貝和深拷貝。這是最可靠的深度克隆方法,不會丟失資料或破壞資料。它的主要功能是合併兩個或更多物件。但是也可以用於克隆物件。它帶有以下引數:[deep]
、target
、object1 ..... objectN
。
[deep]
:這是一個可選引數。它唯一允許的值為 true。如果在函式中傳遞它,則該函式將建立物件的深拷貝。否則,它將形成一個淺拷貝。target
:要擴充套件的物件。它將接收所有合併的物件。object1, ..., objectN
:這些是要合併/克隆到新物件中的物件。
let obj = {
a: 1,
b: {
c: 2
}
}
let shallowClone = $.extend({},obj); // creates a shallow copy
let deepClone = $.extend(true,{}, obj); // creates a deep copy
一個更明顯的解決方案可以是遍歷源物件的每個屬性,然後將它們複製到新物件中。上面討論的所有方法都與所有主要的瀏覽器相容。
Harshit Jindal has done his Bachelors in Computer Science Engineering(2021) from DTU. He has always been a problem solver and now turned that into his profession. Currently working at M365 Cloud Security team(Torus) on Cloud Security Services and Datacenter Buildout Automation.
LinkedIn