在 JavaScript 中如何克隆對(duì)象?
當(dāng)我們想要復(fù)制原始值和引用值(對(duì)象)時(shí),它們的行為會(huì)大不相同。
原始值
我們假設(shè)一個(gè)變量 name 具有一個(gè)與之關(guān)聯(lián)的原始值(number,string,boolean,undefined 和null)。如果我們將此變量 name 復(fù)制到另一個(gè)變量name2 ,則原始變量的任何修改都不會(huì)影響到第二個(gè)變量,因?yàn)樗鼈兪窃贾怠?/p>
- let name="前端小智";
- let name2= name;
- console.log (name, name2); // 前端小智, 前端小智
- name="王大冶";
- console.log (name,name2); // 王大冶 前端小智
引用值
但是,如果我們對(duì)引用類型的值進(jìn)行相同的操作,則我們對(duì)一個(gè)變量所做的任何更改也將反映在另一個(gè)變量中,因?yàn)閮蓚€(gè)變量都指向同一對(duì)象。
數(shù)組
要拷貝數(shù)組,slice()方法用于創(chuàng)建數(shù)組的新副本。可以獨(dú)立修改此副本,而不會(huì)影響原始數(shù)組。
如果未傳遞任何參數(shù),則它會(huì)精確復(fù)制數(shù)組,但數(shù)字也可以作為參數(shù)傳遞。如果僅傳遞一個(gè)數(shù)字,它將確定我們要從其進(jìn)行復(fù)制的索引的值,而如果傳遞兩個(gè)數(shù)字,則將標(biāo)記開始和結(jié)束。
- // 示例1
- const names = ['前端小智', '王大冶', '小力'];
- const names2 = names;
- console.log(names, names2);
- // ["前端小智", "王大冶", "小力"]
- // ["前端小智", "王大冶", "小力"]
- // 示例2
- names2[2] = '前端小力';
- console.log(names, names2);
- // ["前端小智", "王大冶", "前端小力"]
- // ["前端小智", "王大冶", "前端小力"]
- // 示例3
- const name2 = names.slice();
- names[2] = '我是隔壁老智';
- console.log(name2, names2)
- // ["前端小智", "王大冶", "前端小力"]
- // ["前端小智", "王大冶", "我是隔壁老智"]
對(duì)象
當(dāng)引用值是一個(gè)對(duì)象時(shí),也會(huì)發(fā)生同樣的情況,對(duì)其屬性之一的任何修改都會(huì)影響這兩個(gè)變量。若要克隆對(duì)象,請(qǐng)使用 Object.assign()方法,該方法會(huì)將一個(gè)或多個(gè)源對(duì)象的所有可枚舉屬性的值復(fù)制到目標(biāo)對(duì)象,但是此方法僅對(duì)對(duì)象的一個(gè)淺拷貝。
- // 示例1
- const names = {
- name: '前端小智',
- surname: '隔壁老智'
- }
- const names2 = names;
- console.log(names, names2) // 打印結(jié)果是一模一樣的
- // 示例2
- names2.surname ='隔壁老王';
- console.log(names, names2)
- // {name: "前端小智", surname: "隔壁老王"}
- // {name: "前端小智", surname: "隔壁老王"}
- // 示例3
- const names3 = Object.assign({}, names);
- names3.surname = '隔壁老色P';
- console.log(names, names3)
- // {name: "前端小智", surname: "隔壁老王"}
- // {name: "前端小智", surname: "隔壁老色P"}
要對(duì)對(duì)象進(jìn)行深拷貝,需要使用其他方法。
正如我們所說(shuō),Object.assign()方法只是一個(gè)淺拷貝(即,當(dāng)我們的對(duì)象沒有其他對(duì)象作為屬性時(shí))才有效。在這些情況下,必須對(duì)對(duì)象進(jìn)行深拷貝。
與淺拷貝不同,深拷貝以遞歸方式復(fù)制每個(gè)子對(duì)象,直到所有涉及的對(duì)象都被復(fù)制為止。
我們可以使用什么方法復(fù)制對(duì)象的深層副本?
JSON.parse(JSON.stringify(obj))
此方法使用JSON.stringify()將對(duì)象轉(zhuǎn)換為字符串,然后再用JSON.parse()將其轉(zhuǎn)換回對(duì)象。此方法對(duì)簡(jiǎn)單對(duì)象有效,但如果對(duì)象屬性是函數(shù)時(shí)無(wú)效。
- const names = {
- name: '前端小智',
- surname: '隔壁老智',
- social: {
- wx: '大遷世界',
- url: 'www.lsp.com'
- }
- }
- const names2 = JSON.parse(JSON.stringify(names));
- names2.social.url = 'www.baidu.com';
- console.log(names, names2);
- /**
- {
- name: "前端小智"
- social: {wx: "大遷世界", url: "www.lsp.com"}
- surname: "隔壁老智"
- }
- */
- /**
- {
- name: "前端小智"
- social: {wx: "大遷世界", url: "www.baidu.com"}
- surname: "隔壁老智"
- }
- */
深度拷貝
另一種非常有趣和優(yōu)雅的對(duì)象深度復(fù)制方法是使用遞歸函數(shù)。
我們創(chuàng)建了一個(gè)deepClone(object)函數(shù),將想要克隆的對(duì)象作為參數(shù)傳遞給它。在函數(shù)內(nèi)部,將創(chuàng)建一個(gè)局部變量克隆,這是一個(gè)空對(duì)象,其中將從起始對(duì)象克隆的每個(gè)屬性都將添加到該對(duì)象中。
具體思路:
- 如果該屬性不是對(duì)象,則將其簡(jiǎn)單地克隆并添加到新的克隆對(duì)象中。
- 如果屬性是對(duì)象,則再次執(zhí)行deepClone(value)函數(shù),并將屬性的值(在這種情況下為對(duì)象)作為參數(shù)傳遞,并重復(fù)相同的過(guò)程。
- function deepClone(object) {
- var clone = {};
- for (var key in object) {
- var value = object[key];
- if (typeof(value) !== 'object') {
- clone[key] = value;
- } else {
- clone[key]=deepClone(value);
- }
- }
- return clone;
- }
- deepClone({value1:1,value2:{value3:2}});
- //{value1:1,value2:{value3:2}}
- deepClone({value1:1,value2:{value3:{value3b:3}}});
- //{value1:1,value2:{value3:{value3b:3}}}
作者:Luigi Nori 譯者:前端小智 來(lái)源:stackabuse
原文:https://www.ma-o.org/en/programming/javascript/the-javascript-asign-method-to-merge-and-clone-objects






