理解“深拷貝”和“淺拷貝”的區(qū)別

在JavaScript中朴上,拷貝對象或數(shù)組時(shí),我們需要理解“深拷貝”和“淺拷貝”的區(qū)別色查。這兩種拷貝方式在處理嵌套對象或數(shù)組時(shí)表現(xiàn)不同剪勿。

淺拷貝

淺拷貝是指創(chuàng)建一個新的對象或數(shù)組,其元素是對原對象或數(shù)組中元素的引用耻姥。如果原對象或數(shù)組中的元素是基本類型(如數(shù)字销钝、字符串、布爾值)琐簇,那么這些元素會被復(fù)制到新對象或數(shù)組中蒸健。但如果元素是對象或數(shù)組,那么新對象或數(shù)組中的對應(yīng)元素將是對原對象中對應(yīng)元素的引用婉商,而不是一個新的副本似忧。

應(yīng)用場景:
  • 當(dāng)你只需要復(fù)制對象或數(shù)組的第一層結(jié)構(gòu),并且不關(guān)心嵌套對象或數(shù)組的獨(dú)立性時(shí)丈秩。
  • 在性能敏感的場景中盯捌,淺拷貝比深拷貝更快,因?yàn)樗恍枰f歸地復(fù)制所有嵌套元素蘑秽。
實(shí)例代碼:
// 淺拷貝對象
const originalObject = { a: 1, b: { c: 2 } };
const shallowCopy = Object.assign({}, originalObject);
 
originalObject.b.c = 3;
console.log(shallowCopy.b.c); // 輸出 3饺著,因?yàn)閎屬性仍然引用原對象中的嵌套對象
 
// 淺拷貝數(shù)組
const originalArray = [1, 2, { a: 3 }];
const shallowCopyArray = originalArray.slice();
 
originalArray[2].a = 4;
console.log(shallowCopyArray[2].a); // 輸出 4,因?yàn)閿?shù)組中的對象仍然是原對象中的引用
  • 對象擴(kuò)展運(yùn)算符(...):

對象擴(kuò)展運(yùn)算符可以用于將一個對象的所有可枚舉屬性復(fù)制到另一個新對象中肠牲。

const original = { a: 1, b: 2 };
const copy = { ...original };
copy.a = 3;
console.log(original.a); // 輸出 1瓶籽,原對象未受影響
  • Object.assign() 方法:

Object.assign 方法可以將一個或多個源對象的所有可枚舉屬性復(fù)制到目標(biāo)對象中,并返回目標(biāo)對象埂材。

const original = { a: 1, b: 2 };
const copy = Object.assign({}, original);
copy.a = 3;
console.log(original.a); // 輸出 1塑顺,原對象未受影響
  • 數(shù)組方法 slice() 和 concat():

對于數(shù)組,可以使用 slice() 方法或 concat() 方法來創(chuàng)建淺拷貝俏险。
slice() 方法返回一個新的數(shù)組對象严拒,這一新的數(shù)組對象是一個從原數(shù)組中淺拷貝出來的部分,原數(shù)組不會被修改竖独。

const originalArray = [1, 2, 3];
const copyArray = originalArray.slice();
copyArray[0] = 4;
console.log(originalArray[0]); // 輸出 1裤唠,原數(shù)組未受影響

concat() 方法也可以用于淺拷貝數(shù)組,它返回一個新數(shù)組莹痢,該數(shù)組是原數(shù)組與傳入的數(shù)組/值連接后的一個新數(shù)組种蘸。如果只傳入一個空數(shù)組作為參數(shù)墓赴,就相當(dāng)于創(chuàng)建了一個原數(shù)組的淺拷貝。

const originalArray = [1, 2, 3];
const copyArray = originalArray.concat();
copyArray[0] = 4;
console.log(originalArray[0]); // 輸出 1航瞭,原數(shù)組未受影響
  • Array.from() 方法:

Array.from() 方法可以從類似數(shù)組或可迭代對象中創(chuàng)建一個新的诫硕、淺拷貝的數(shù)組實(shí)例。

const originalArray = [1, 2, 3];
const copyArray = Array.from(originalArray);
copyArray[0] = 4;
console.log(originalArray[0]); // 輸出 1刊侯,原數(shù)組未受影響
  • 直接賦值(對于非對象和數(shù)組的基本類型):

如果值是非對象(例如數(shù)字章办、字符串、布爾值)滨彻,則直接賦值就會創(chuàng)建一個新的副本藕届,因?yàn)榛绢愋褪前粗祩鬟f的。

let original = 42;
let copy = original;
copy = 43;
console.log(original); // 輸出 42亭饵,原值未受影響

但是休偶,如果值是一個對象或數(shù)組,直接賦值將不會創(chuàng)建副本辜羊,而是創(chuàng)建一個指向原對象或數(shù)組的引用踏兜。

深拷貝

深拷貝是指創(chuàng)建一個新的對象或數(shù)組,并且遞歸地復(fù)制所有嵌套的對象或數(shù)組只冻,使得新對象或數(shù)組與原對象或數(shù)組完全獨(dú)立庇麦。深拷貝會占用更多的內(nèi)存计技,并且執(zhí)行速度較慢喜德,因?yàn)樗枰f歸地處理所有嵌套元素。

應(yīng)用場景:
  • 當(dāng)你需要復(fù)制一個對象或數(shù)組垮媒,并且希望新對象或數(shù)組與原對象或數(shù)組完全獨(dú)立時(shí)舍悯。
  • 在處理包含復(fù)雜嵌套結(jié)構(gòu)的數(shù)據(jù)時(shí),如配置對象睡雇、狀態(tài)樹等萌衬。
實(shí)例代碼:

使用JSON.parse和JSON.stringify進(jìn)行深拷貝(這種方法有局限性,不能處理函數(shù)它抱、undefined秕豫、NaN、循環(huán)引用等):

const originalObject = { a: 1, b: { c: 2 } };
const deepCopy = JSON.parse(JSON.stringify(originalObject));

originalObject.b.c = 3;
console.log(deepCopy.b.c); // 輸出 2观蓄,因?yàn)樯羁截悇?chuàng)建了一個新的嵌套對象

// 注意:這種方法不適用于數(shù)組中包含函數(shù)或其他特殊值的情況
深拷貝與 JSON.stringify

當(dāng)你使用 JSON.parse(JSON.stringify(obj)) 作為深拷貝的一種手段時(shí)混移,你需要注意上述行為。特別是侮穿,如果你的對象中包含函數(shù)歌径、undefined、Symbol亲茅、循環(huán)引用回铛、Infinity狗准、NaN、Date 或 RegExp茵肃,那么這種方法可能不會按預(yù)期工作腔长。

示例

const original = {
  a: 1,
  b: undefined,
  c: function() {},
  d: Symbol('d'),
  e: Infinity,
  f: NaN,
  g: new Date(),
  h: /hello/,
  i: { j: 1, k: { l: 2 } }
};
 
const copy = JSON.parse(JSON.stringify(original));
 
console.log(copy);
// 輸出:
// {
//   a: 1,
//   i: { j: 1, k: { l: 2 } },
//   g: "2023-04-01T12:00:00.000Z" (日期會被轉(zhuǎn)換為 ISO 格式字符串)
// }
// 注意:b, c, d, e, f, h 屬性都丟失了或者被轉(zhuǎn)換了

在這個例子中,你可以看到 b(undefined)免姿、c(函數(shù))饼酿、d(Symbol)、e(Infinity)胚膊、f(NaN)故俐、h(RegExp)屬性都沒有被復(fù)制到新對象中,而 g(Date 對象)被轉(zhuǎn)換為了一個字符串紊婉。只有 a 和 i(嵌套對象)被正確地復(fù)制了药版。

使用遞歸函數(shù)進(jìn)行深拷貝(更通用,但也需要小心處理循環(huán)引用):
function deepClone(obj) {
  if (obj === null || typeof obj !== 'object') {
    return obj;
  }
 
  if (Array.isArray(obj)) {
    return obj.map(item => deepClone(item));
  }
 
  const copy = {};
  for (let key in obj) {
    if (obj.hasOwnProperty(key)) {
      copy[key] = deepClone(obj[key]);
    }
  }
  return copy;
}
 
const originalObject = { a: 1, b: { c: 2 } };
const deepCopy = deepClone(originalObject);
 
originalObject.b.c = 3;
console.log(deepCopy.b.c); // 輸出 2喻犁,因?yàn)樯羁截悇?chuàng)建了一個新的嵌套對象

在實(shí)際應(yīng)用中槽片,選擇淺拷貝還是深拷貝取決于你的具體需求。如果你只需要復(fù)制對象或數(shù)組的第一層結(jié)構(gòu)肢础,并且不關(guān)心嵌套元素的獨(dú)立性还栓,那么淺拷貝就足夠了。如果你需要完全獨(dú)立的副本传轰,包括所有嵌套的對象和數(shù)組剩盒,那么你應(yīng)該使用深拷貝。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末慨蛙,一起剝皮案震驚了整個濱河市辽聊,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌期贫,老刑警劉巖跟匆,帶你破解...
    沈念sama閱讀 217,185評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異通砍,居然都是意外死亡玛臂,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,652評論 3 393
  • 文/潘曉璐 我一進(jìn)店門封孙,熙熙樓的掌柜王于貴愁眉苦臉地迎上來迹冤,“玉大人,你說我怎么就攤上這事敛瓷∪蓿” “怎么了?”我有些...
    開封第一講書人閱讀 163,524評論 0 353
  • 文/不壞的土叔 我叫張陵呐籽,是天一觀的道長锋勺。 經(jīng)常有香客問我蚀瘸,道長,這世上最難降的妖魔是什么庶橱? 我笑而不...
    開封第一講書人閱讀 58,339評論 1 293
  • 正文 為了忘掉前任贮勃,我火速辦了婚禮,結(jié)果婚禮上苏章,老公的妹妹穿的比我還像新娘寂嘉。我一直安慰自己,他們只是感情好枫绅,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,387評論 6 391
  • 文/花漫 我一把揭開白布泉孩。 她就那樣靜靜地躺著,像睡著了一般并淋。 火紅的嫁衣襯著肌膚如雪寓搬。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,287評論 1 301
  • 那天县耽,我揣著相機(jī)與錄音句喷,去河邊找鬼。 笑死兔毙,一個胖子當(dāng)著我的面吹牛唾琼,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播澎剥,決...
    沈念sama閱讀 40,130評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼锡溯,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了肴裙?” 一聲冷哼從身側(cè)響起趾唱,我...
    開封第一講書人閱讀 38,985評論 0 275
  • 序言:老撾萬榮一對情侶失蹤涌乳,失蹤者是張志新(化名)和其女友劉穎蜻懦,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體夕晓,經(jīng)...
    沈念sama閱讀 45,420評論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡宛乃,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,617評論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了蒸辆。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片征炼。...
    茶點(diǎn)故事閱讀 39,779評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖躬贡,靈堂內(nèi)的尸體忽然破棺而出谆奥,到底是詐尸還是另有隱情,我是刑警寧澤拂玻,帶...
    沈念sama閱讀 35,477評論 5 345
  • 正文 年R本政府宣布酸些,位于F島的核電站宰译,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏魄懂。R本人自食惡果不足惜沿侈,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,088評論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望市栗。 院中可真熱鬧缀拭,春花似錦、人聲如沸填帽。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,716評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽篡腌。三九已至铣鹏,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間哀蘑,已是汗流浹背诚卸。 一陣腳步聲響...
    開封第一講書人閱讀 32,857評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留绘迁,地道東北人合溺。 一個月前我還...
    沈念sama閱讀 47,876評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像缀台,于是被迫代替她去往敵國和親棠赛。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,700評論 2 354

推薦閱讀更多精彩內(nèi)容