如何在JavaScript中復(fù)制一個(gè)對(duì)象?
JavaScript的原始數(shù)據(jù)類(lèi)型是不可變的,這意味著一旦創(chuàng)建,它們的值就不能改變。但是,對(duì)象和數(shù)組是可變的,允許在創(chuàng)建后修改它們的值。
實(shí)際上,這意味著原始數(shù)據(jù)是通過(guò)值傳遞的,而對(duì)象和數(shù)組是通過(guò)引用傳遞的。考慮以下例子:
let str = 'Hello';
let copy = str;
copy = 'Hi';
// str = 'Hello', copy = 'Hi'
let obj = { a: 1, b: 2 };
let objCopy = obj;
objCopy.b = 4;
// obj = { a: 1, b: 4}, objCopy = { a: 1, b: 4 }
你可以看到,對(duì)象obj是通過(guò)引用傳遞給objCopy的。修改其中一個(gè)變量會(huì)影響另一個(gè)變量,因?yàn)樗鼈兌家猛粋€(gè)對(duì)象。那我們?nèi)绾谓鉀Q這個(gè)問(wèn)題呢?答案是克隆對(duì)象。
淺復(fù)制
使用展開(kāi)運(yùn)算符(...)或 Object.assign(),我們可以克隆對(duì)象并根據(jù)其屬性創(chuàng)建一個(gè)新對(duì)象。
const shallowClone = obj => Object.assign({}, obj);
let obj = { a: 1, b: 2};
let clone = shallowClone(obj);
let otherClone = shallowClone(obj);
clone.b = 4;
otherClone.b = 6;
// obj = { a: 1, b: 2}
// clone = { a: 1, b: 4 }
// otherClone = { a: 1, b: 6 }
這種技術(shù)被稱(chēng)為淺復(fù)制,因?yàn)樗m用于外部(淺層)對(duì)象,但如果我們有嵌套(深層)對(duì)象,則會(huì)失敗,因?yàn)檫@些對(duì)象最終會(huì)通過(guò)引用傳遞。這就引出了下一部分。
圖片
深復(fù)制
為了創(chuàng)建一個(gè)對(duì)象的深復(fù)制,我們需要遞歸地克隆每一個(gè)嵌套對(duì)象,復(fù)制嵌套對(duì)象和數(shù)組。
網(wǎng)上有一些解決方案使用 JSON.stringify() 和 JSON.parse()。雖然這種方法在某些情況下可能有效,但它包含許多問(wèn)題和性能問(wèn)題,因此我建議不要使用它。
從邊界情況開(kāi)始,我們需要檢查傳遞的對(duì)象是否為空,如果是,則返回 null。否則,我們可以使用 Object.assign() 和一個(gè)空對(duì)象 ({}) 來(lái)創(chuàng)建原始對(duì)象的淺復(fù)制。
然后,我們將使用 Object.keys() 和 Array.prototype.forEach() 來(lái)確定需要深復(fù)制哪些鍵值對(duì)。如果對(duì)象是一個(gè)數(shù)組,我們將設(shè)置克隆對(duì)象的長(zhǎng)度與原對(duì)象相等,并使用 Array.from() 創(chuàng)建一個(gè)克隆對(duì)象。否則,我們將遞歸地調(diào)用函數(shù),把當(dāng)前值作為參數(shù)傳入。
深復(fù)制專(zhuān)用于簡(jiǎn)單對(duì)象和數(shù)組。這意味著它無(wú)法處理類(lèi)實(shí)例,函數(shù)和其他特殊情況。那么,我們?nèi)绾翁幚磉@些情況呢?JavaScript最近給我們提供了一個(gè)新的工具來(lái)解決這個(gè)問(wèn)題!
使用 structuredClone() 進(jìn)行深復(fù)制
克隆顯然是一個(gè)很常見(jiàn)也很重要的問(wèn)題。事實(shí)上,JavaScript引入了structuredClone()全局函數(shù),可以用來(lái)深度克隆對(duì)象。而我們不需要實(shí)現(xiàn)復(fù)雜的遞歸函數(shù),只需使用這個(gè)函數(shù)就可以克隆對(duì)象。
這種技術(shù)可用于數(shù)組和對(duì)象,代碼最少,是JavaScript中克隆對(duì)象的推薦方式,因?yàn)樗阅茏罴亚易羁煽俊?/p>