国产av日韩一区二区三区精品,成人性爱视频在线观看,国产,欧美,日韩,一区,www.成色av久久成人,2222eeee成人天堂

目錄
關(guān)鍵要點
什么是“淺”復制
深復制
如何使用 JSON.stringify()JSON.parse() 進行深復制
用于深復制的庫
Vanilla JS 深復制函數(shù)
深復制的缺點
結(jié)論
關(guān)于 JavaScript 中淺復制與深復制的常見問題解答 (FAQ)
JavaScript 中淺復制和深復制的主要區(qū)別是什么?
展開運算符如何在淺復制中工作?
我可以使用 JSON 方法進行深復制嗎?
淺復制的局限性是什么?
在 JavaScript 中深復制對象的最佳方法是什么?
我可以使用展開運算符進行深復制嗎?
深復制的性能影響是什么?
深復制如何處理循環(huán)引用?
為什么我應該關(guān)心淺復制和深復制之間的區(qū)別?
首頁 web前端 js教程 淺與深層復制的JavaScript

淺與深層復制的JavaScript

Feb 09, 2025 am 08:28 AM

Shallow vs. Deep Copying in JavaScript

JavaScript 對象的復制并非表面看起來那么簡單。理解此過程中對象和引用的工作方式對于 Web 開發(fā)人員至關(guān)重要,可以節(jié)省數(shù)小時的調(diào)試時間。當您使用大型有狀態(tài)應用程序(例如在 React 或 Vue 中構(gòu)建的應用程序)時,這一點變得越來越重要。

淺復制和深復制指的是我們在 JavaScript 中如何創(chuàng)建對象的副本以及在“副本”中創(chuàng)建了哪些數(shù)據(jù)。在本文中,我們將深入探討這些方法之間的區(qū)別,探討它們的實際應用,并揭示使用它們時可能出現(xiàn)的潛在陷阱。

關(guān)鍵要點

  • JavaScript 中的淺復制創(chuàng)建一個新對象,該對象復制現(xiàn)有對象的屬性,但保留對原始值或?qū)ο蟮南嗤谩_@意味著對淺副本中嵌套對象的修改也會影響原始對象和任何其他淺副本。
  • 另一方面,深復制會創(chuàng)建現(xiàn)有對象的精確副本,包括其所有屬性和任何嵌套對象,而不是僅僅是引用。當您需要兩個不共享引用的獨立對象時,這使得深復制變得有益,從而確保對一個對象的更改不會影響另一個對象。
  • 雖然深復制提供了數(shù)據(jù)準確性的好處,但它也可能存在一些缺點,例如性能影響、內(nèi)存消耗增加、循環(huán)引用問題、函數(shù)和特殊對象處理以及實現(xiàn)復雜性。因此,務必評估對于每個特定用例是否需要深復制。

什么是“淺”復制

淺復制是指創(chuàng)建新對象的過程,該對象是現(xiàn)有對象的副本,其屬性引用與原始對象相同的數(shù)值或?qū)ο蟆T?JavaScript 中,這通常是使用 Object.assign() 或展開語法({...originalObject})等方法實現(xiàn)的。淺復制僅創(chuàng)建對現(xiàn)有對象或值的新的引用,不會創(chuàng)建深復制,這意味著嵌套對象仍然是引用的,而不是重復的。

讓我們看看下面的代碼示例。新創(chuàng)建的對象 shallowCopyZoo 是通過展開運算符創(chuàng)建的 zoo 的副本,這導致了一些意外的后果。

let zoo = {
  name: "Amazing Zoo",
  location: "Melbourne, Australia",
  animals: [
    {
      species: "Lion",
      favoriteTreat: "?",
    },
    {
      species: "Panda",
      favoriteTreat: "?",
    },
  ],
};

let shallowCopyZoo = { ...zoo };
shallowCopyZoo.animals[0].favoriteTreat = "?";
console.log(zoo.animals[0].favoriteTreat); 
// "?",而不是 "?"

但是讓我們看看 shallowCopyZoo 中究竟是什么。屬性 namelocation 是原始值(字符串),因此它們的數(shù)值被復制。但是,animals 屬性是對象的數(shù)組,因此復制的是對該數(shù)組的引用,而不是數(shù)組本身。

您可以使用嚴格相等運算符 (===) 快速測試這一點(如果您不相信我)。只有當對象引用同一對象時,一個對象才等于另一個對象(參見原始數(shù)據(jù)類型與引用數(shù)據(jù)類型)。請注意,animals 屬性在兩者上是相等的,但對象本身并不相等。

let zoo = {
  name: "Amazing Zoo",
  location: "Melbourne, Australia",
  animals: [
    {
      species: "Lion",
      favoriteTreat: "?",
    },
    {
      species: "Panda",
      favoriteTreat: "?",
    },
  ],
};

let shallowCopyZoo = { ...zoo };
shallowCopyZoo.animals[0].favoriteTreat = "?";
console.log(zoo.animals[0].favoriteTreat); 
// "?",而不是 "?"

這可能導致代碼庫中出現(xiàn)潛在問題,并且在處理大型修改時尤其困難。修改淺副本中的嵌套對象也會影響原始對象和任何其他淺副本,因為它們都共享相同的引用。

深復制

深復制是一種創(chuàng)建新對象的技巧,該對象是現(xiàn)有對象的精確副本。這包括復制其所有屬性和任何嵌套對象,而不是引用。當您需要兩個不共享引用的獨立對象時,深克隆很有用,確保對一個對象的更改不會影響另一個對象。

程序員在處理復雜應用程序中的應用程序狀態(tài)對象時經(jīng)常使用深克隆。創(chuàng)建新的狀態(tài)對象而不影響先前狀態(tài)對于維護應用程序的穩(wěn)定性和正確實現(xiàn)撤消/重做功能至關(guān)重要。

如何使用 JSON.stringify()JSON.parse() 進行深復制

一種流行且無需庫的深復制方法是使用內(nèi)置的 JSON.stringify()JSON.parse() 方法。

parse(stringify()) 方法并不完美。例如,Date 等特殊數(shù)據(jù)類型將被轉(zhuǎn)換為字符串,未定義的值將被忽略。與本文中的所有選項一樣,應根據(jù)您的具體用例進行考慮。

在下面的代碼中,我們將使用這些方法創(chuàng)建一個 deepCopy 函數(shù)來深度克隆一個對象。然后,我們復制 playerProfile 對象并修改復制的對象,而不會影響原始對象。這展示了深復制在維護不共享引用的獨立對象方面的價值。

console.log(zoo.animals === shallowCopyZoo.animals)
// true

console.log(zoo === shallowCopyZoo)
// false

用于深復制的庫

還有一些各種第三方庫提供了深復制解決方案。

  • Lodash 庫的 cloneDeep() 函數(shù)可以正確處理循環(huán)引用、函數(shù)和特殊對象。
  • jQuery 庫的 extend() [deep = true] 函數(shù)
  • immer 庫是為 React-Redux 開發(fā)人員構(gòu)建的,并提供用于修改對象的便捷工具。

Vanilla JS 深復制函數(shù)

如果由于某種原因您不想使用 JSON 對象或第三方庫,您也可以在 Vanilla JavaScript 中創(chuàng)建一個自定義深復制函數(shù)。該函數(shù)遞歸迭代對象屬性并創(chuàng)建一個具有相同屬性和值的新對象。

const playerProfile = {
  name: 'Alice',
  level: 10,
  achievements: [
    {
      title: 'Fast Learner',
      emoji: '?'
    },
    {
      title: 'Treasure Hunter',
      emoji: '?'
    }
  ]
};

function deepCopy(obj) {
  return JSON.parse(JSON.stringify(obj));
}

const clonedProfile = deepCopy(playerProfile);

console.log(clonedProfile);
// 輸出與playerProfile相同

// 修改克隆的配置文件而不影響原始配置文件
clonedProfile.achievements.push({ title: 'Marathon Runner', emoji: '?' });
console.log(playerProfile.achievements.length); // 輸出:2
console.log(clonedProfile.achievements.length); // 輸出:3

深復制的缺點

雖然深復制為數(shù)據(jù)準確性提供了極大的好處,但建議評估對于每個特定用例是否需要深復制。在某些情況下,淺復制或其他管理對象引用的技術(shù)可能更合適,從而提供更好的性能和降低復雜性。

  1. 性能影響:深復制在計算上可能代價高昂,尤其是在處理大型或復雜對象時。由于深復制過程會迭代所有嵌套屬性,因此可能需要大量時間,從而對應用程序的性能產(chǎn)生負面影響。
  2. 內(nèi)存消耗:創(chuàng)建深復制會導致復制整個對象層次結(jié)構(gòu),包括所有嵌套對象。這可能導致內(nèi)存使用增加,這在內(nèi)存受限的環(huán)境中或處理大型數(shù)據(jù)集時可能成為問題。
  3. 循環(huán)引用:當對象包含循環(huán)引用(即當一個對象的屬性直接或間接地引用自身時)時,深復制可能會導致問題。循環(huán)引用可能導致深復制過程中的無限循環(huán)或堆棧溢出錯誤,處理它們需要額外的邏輯來避免這些問題。
  4. 函數(shù)和特殊對象處理:深復制可能無法按預期處理函數(shù)或具有特殊特征的對象(例如,Date、RegExp、DOM 元素)。例如,當深復制包含函數(shù)的對象時,可能會復制函數(shù)的引用,但不會復制函數(shù)的閉包及其綁定的上下文。同樣,具有特殊特征的對象在深復制時可能會丟失其獨特的屬性和行為。
  5. 實現(xiàn)復雜性:編寫自定義深復制函數(shù)可能很復雜,而像 JSON.parse(JSON.stringify(obj)) 這樣的內(nèi)置方法也有一些限制,例如無法正確處理函數(shù)、循環(huán)引用或特殊對象。雖然有一些第三方庫(如 Lodash 的 _.cloneDeep())可以更有效地處理深復制,但為深復制添加外部依賴項可能并不總是理想的。

結(jié)論

感謝您抽出時間閱讀本文。淺復制與深復制比任何初學者想象的都要復雜得多。盡管每種方法都有很多陷阱,但花時間審查和考慮這些選項將確保您的應用程序和數(shù)據(jù)保持您想要的樣子。

關(guān)于 JavaScript 中淺復制與深復制的常見問題解答 (FAQ)

JavaScript 中淺復制和深復制的主要區(qū)別是什么?

淺復制和深復制之間的主要區(qū)別在于它們處理作為對象的屬性的方式。在淺復制中,復制的對象與原始對象共享對嵌套對象的相同引用。這意味著對嵌套對象的更改將反映在原始對象和復制對象中。另一方面,深復制會創(chuàng)建嵌套對象的新實例,這意味著對復制對象中嵌套對象的更改不會影響原始對象。

展開運算符如何在淺復制中工作?

JavaScript 中的展開運算符(…)通常用于淺復制。它將一個對象的所有可枚舉自身屬性復制到另一個對象。但是,它只復制第一級的屬性和嵌套對象的引用。因此,對嵌套對象的更改將影響原始對象和復制的對象。

我可以使用 JSON 方法進行深復制嗎?

是的,您可以使用 JSON 方法在 JavaScript 中進行深復制。JSON.stringify()JSON.parse() 方法的組合可以創(chuàng)建對象的深復制。JSON.stringify() 將對象轉(zhuǎn)換為字符串,JSON.parse() 將字符串解析回新對象。但是,此方法有一些限制,因為它不會復制方法,并且不適用于 Date、RegExpMap、Set 等特殊 JavaScript 對象。

淺復制的局限性是什么?

淺復制只復制第一級的屬性和嵌套對象的引用。因此,如果原始對象包含嵌套對象,則對這些嵌套對象的更改將影響原始對象和復制的對象。這可能導致代碼中出現(xiàn)意外的結(jié)果和錯誤。

Object.assign() 方法如何在淺復制中工作?

Object.assign() 方法用于將一個或多個源對象的所有可枚舉自身屬性的值復制到目標對象。它返回目標對象。但是,它執(zhí)行淺復制,這意味著它只復制第一級的屬性和嵌套對象的引用。

在 JavaScript 中深復制對象的最佳方法是什么?

在 JavaScript 中深復制對象的最佳方法取決于代碼的具體要求。如果您的對象不包含方法或特殊的 JavaScript 對象,您可以使用 JSON.stringify()JSON.parse() 方法的組合。對于更復雜的對象,您可能需要使用 Lodash 等庫,該庫提供深克隆函數(shù)。

我可以使用展開運算符進行深復制嗎?

不可以,JavaScript 中的展開運算符只執(zhí)行淺復制。它復制第一級的屬性和嵌套對象的引用。要執(zhí)行深復制,您需要使用其他方法或庫。

深復制的性能影響是什么?

深復制可能比淺復制更消耗資源,尤其對于大型對象而言。這是因為深復制為所有嵌套對象創(chuàng)建新實例,這可能會占用更多內(nèi)存和處理能力。

深復制如何處理循環(huán)引用?

JSON.stringify()JSON.parse() 等深復制方法不處理循環(huán)引用,并將拋出錯誤。循環(huán)引用發(fā)生在一個對象的屬性引用該對象本身時。要處理循環(huán)引用,您需要使用支持它的庫,例如 Lodash。

為什么我應該關(guān)心淺復制和深復制之間的區(qū)別?

了解淺復制和深復制之間的區(qū)別對于管理 JavaScript 中的數(shù)據(jù)至關(guān)重要。它會影響您的對象如何相互交互。如果您不小心,淺復制會導致意外的結(jié)果和錯誤,因為對嵌套對象的更改會影響原始對象和復制的對象。另一方面,深復制確保您的復制對象與原始對象完全獨立。

以上是淺與深層復制的JavaScript的詳細內(nèi)容。更多信息請關(guān)注PHP中文網(wǎng)其他相關(guān)文章!

本站聲明
本文內(nèi)容由網(wǎng)友自發(fā)貢獻,版權(quán)歸原作者所有,本站不承擔相應法律責任。如您發(fā)現(xiàn)有涉嫌抄襲侵權(quán)的內(nèi)容,請聯(lián)系admin@php.cn

熱AI工具

Undress AI Tool

Undress AI Tool

免費脫衣服圖片

Undresser.AI Undress

Undresser.AI Undress

人工智能驅(qū)動的應用程序,用于創(chuàng)建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用于從照片中去除衣服的在線人工智能工具。

Clothoff.io

Clothoff.io

AI脫衣機

Video Face Swap

Video Face Swap

使用我們完全免費的人工智能換臉工具輕松在任何視頻中換臉!

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的代碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

功能強大的PHP集成開發(fā)環(huán)境

Dreamweaver CS6

Dreamweaver CS6

視覺化網(wǎng)頁開發(fā)工具

SublimeText3 Mac版

SublimeText3 Mac版

神級代碼編輯軟件(SublimeText3)

如何在JS中與日期和時間合作? 如何在JS中與日期和時間合作? Jul 01, 2025 am 01:27 AM

JavaScript中的日期和時間處理需注意以下幾點:1.創(chuàng)建Date對象有多種方式,推薦使用ISO格式字符串以保證兼容性;2.獲取和設置時間信息可用get和set方法,注意月份從0開始;3.手動格式化日期需拼接字符串,也可使用第三方庫;4.處理時區(qū)問題建議使用支持時區(qū)的庫,如Luxon。掌握這些要點能有效避免常見錯誤。

為什么要將標簽放在的底部? 為什么要將標簽放在的底部? Jul 02, 2025 am 01:22 AM

PlacingtagsatthebottomofablogpostorwebpageservespracticalpurposesforSEO,userexperience,anddesign.1.IthelpswithSEObyallowingsearchenginestoaccesskeyword-relevanttagswithoutclutteringthemaincontent.2.Itimprovesuserexperiencebykeepingthefocusonthearticl

什么是在DOM中冒泡和捕獲的事件? 什么是在DOM中冒泡和捕獲的事件? Jul 02, 2025 am 01:19 AM

事件捕獲和冒泡是DOM中事件傳播的兩個階段,捕獲是從頂層向下到目標元素,冒泡是從目標元素向上傳播到頂層。1.事件捕獲通過addEventListener的useCapture參數(shù)設為true實現(xiàn);2.事件冒泡是默認行為,useCapture設為false或省略;3.可使用event.stopPropagation()阻止事件傳播;4.冒泡支持事件委托,提高動態(tài)內(nèi)容處理效率;5.捕獲可用于提前攔截事件,如日志記錄或錯誤處理。了解這兩個階段有助于精確控制JavaScript響應用戶操作的時機和方式。

JavaScript模塊上的確定JS綜述:ES模塊與COMPORJS JavaScript模塊上的確定JS綜述:ES模塊與COMPORJS Jul 02, 2025 am 01:28 AM

ES模塊和CommonJS的主要區(qū)別在于加載方式和使用場景。1.CommonJS是同步加載,適用于Node.js服務器端環(huán)境;2.ES模塊是異步加載,適用于瀏覽器等網(wǎng)絡環(huán)境;3.語法上,ES模塊使用import/export,且必須位于頂層作用域,而CommonJS使用require/module.exports,可在運行時動態(tài)調(diào)用;4.CommonJS廣泛用于舊版Node.js及依賴它的庫如Express,ES模塊則適用于現(xiàn)代前端框架和Node.jsv14 ;5.雖然可混合使用,但容易引發(fā)問題

如何在node.js中提出HTTP請求? 如何在node.js中提出HTTP請求? Jul 13, 2025 am 02:18 AM

在Node.js中發(fā)起HTTP請求有三種常用方式:使用內(nèi)置模塊、axios和node-fetch。1.使用內(nèi)置的http/https模塊無需依賴,適合基礎場景,但需手動處理數(shù)據(jù)拼接和錯誤監(jiān)聽,例如用https.get()獲取數(shù)據(jù)或通過.write()發(fā)送POST請求;2.axios是基于Promise的第三方庫,語法簡潔且功能強大,支持async/await、自動JSON轉(zhuǎn)換、攔截器等,推薦用于簡化異步請求操作;3.node-fetch提供類似瀏覽器fetch的風格,基于Promise且語法簡單

編寫清潔和可維護的JavaScript代碼的最佳實踐是什么? 編寫清潔和可維護的JavaScript代碼的最佳實踐是什么? Jun 23, 2025 am 12:35 AM

要寫出干凈、可維護的JavaScript代碼,應遵循以下四點:1.使用清晰一致的命名規(guī)范,變量名用名詞如count,函數(shù)名用動詞開頭如fetchData(),類名用PascalCase如UserProfile;2.避免過長函數(shù)和副作用,每個函數(shù)只做一件事,如將更新用戶信息拆分為formatUser、saveUser和renderUser;3.合理使用模塊化和組件化,如在React中將頁面拆分為UserProfile、UserStats等小組件;4.寫注釋和文檔時點到為止,重點說明關(guān)鍵邏輯、算法選

垃圾收集如何在JavaScript中起作用? 垃圾收集如何在JavaScript中起作用? Jul 04, 2025 am 12:42 AM

JavaScript的垃圾回收機制通過標記-清除算法自動管理內(nèi)存,以減少內(nèi)存泄漏風險。引擎從根對象出發(fā)遍歷并標記活躍對象,未被標記的則被視為垃圾并被清除。例如,當對象不再被引用(如將變量設為null),它將在下一輪回收中被釋放。常見的內(nèi)存泄漏原因包括:①未清除的定時器或事件監(jiān)聽器;②閉包中對外部變量的引用;③全局變量持續(xù)持有大量數(shù)據(jù)。V8引擎通過分代回收、增量標記、并行/并發(fā)回收等策略優(yōu)化回收效率,降低主線程阻塞時間。開發(fā)時應避免不必要的全局引用、及時解除對象關(guān)聯(lián),以提升性能與穩(wěn)定性。

See all articles