深拷貝和淺拷貝

一、淺拷貝

在JavaScript中,拷貝可以看成是將一個數據類型中的值,複製到另一個數據類型中的過程。淺拷貝是將原始對象第一層屬性的內存地址複製到目標對象的內存地址中,換言之,淺拷貝只是複製了內存中的地址,兩邊操作同一塊內存,也因此在淺拷貝中,改變其中一個變量可能會對另一個變量產生影響。

舉個例子:

let obj1 = { a: 1, b: { c: 2 } };
let obj2 = Object.assign({}, obj1);
obj1.a = 4; 
console.log(obj2.a); // 輸出:1

在上面的例子中,我們將obj1複製到obj2中,然後修改obj1的a屬性為4,那麼obj2的a屬性不會被改變,還是保持原來的1。這是因為,Object.assign()是淺拷貝,只是將第一層屬性值複製到了新的變量中,所以obj2中的值是和obj1相同,但是兩者是不同的變量。

二、深拷貝

相對淺拷貝,深拷貝就是將原始對象的所有屬性(包括第一層和嵌套的屬性)遞歸地複製到目標對象中。在JavaScript中,我們通常使用遞歸的方式來實現深拷貝。

舉個例子:

let obj1 = { a: 1, b: { c: 2 } };
let obj2 = JSON.parse(JSON.stringify(obj1));
obj1.b.c = 3; 
console.log(obj2.b.c); // 輸出:2

在上面的例子中,我們使用JSON.stringify將obj1轉成字符串,再用JSON.parse將其轉成對象,這樣就可以實現深拷貝了。當我們改變obj1的b屬性中的c屬性的值時,obj2並不會被改變,因為obj1和obj2是不同的變量。

三、淺拷貝的實現方式

JavaScript中,我們可以使用以下方式來實現淺拷貝:

1. Object.assign()

Object.assign()方法可以將一個或多個源對象的所有可枚舉屬性複製到目標對象中,並返回目標對象。只有第一層屬性值被複制,如果存在相同屬性,後面的屬性會覆蓋前面的屬性。注意,Object.assign()是淺拷貝,只複製第一層屬性。

let obj1 = { a: 1, b: { c: 2 } };
let obj2 = Object.assign({}, obj1);

2. 擴展運算符

擴展運算符可以將一個對象的可枚舉屬性拷貝到另一個對象中,同樣只能實現淺拷貝。

let obj1 = { a: 1, b: { c: 2 } };
let obj2 = {...obj1};

四、深拷貝的實現方式

JavaScript中,我們可以使用以下方式來實現深拷貝:

1. 遞歸實現

遞歸實現深拷貝是最常用的實現方式。通過遞歸將嵌套對象的每一層都複製到新的變量中,從而實現了完整的拷貝。需要注意的是,在遇到循環引用或者包含函數等其他類型時,需要進行特殊處理。

function deepClone(obj){
    if(typeof obj !== 'object' || obj === null){
        return obj;
    }
    let newObj = Array.isArray(obj) ? [] : {};
    for(let key in obj){
        newObj[key] = deepClone(obj[key]);
    }
    return newObj;
}
let obj1 = { a: 1, b: { c: 2 } };
let obj2 = deepClone(obj1);

2. JSON.parse & JSON.stringify

我們前面已經提到過,可以使用JSON.stringify將對象轉成字符串,然後再用JSON.parse將其轉成對象,從而實現深拷貝。需要注意的是,使用JSON.stringify & JSON.parse無法拷貝函數和循環引用。

let obj1 = { a: 1, b: { c: 2 } };
let obj2 = JSON.parse(JSON.stringify(obj1));

3. Lodash庫

Lodash是一個流行的JavaScript實用工具庫,其中提供了_.cloneDeep方法,支持深拷貝。

let obj1 = { a: 1, b: { c: 2 } };
let obj2 = _.cloneDeep(obj1);

五、總結

在JavaScript中,淺拷貝和深拷貝是兩種常用的拷貝方式。淺拷貝只複製第一層的屬性,複製後的變量和原變量指向同一塊內存;深拷貝則遞歸複製所有的屬性,複製後的變量和原變量是完全獨立的變量。淺拷貝可以使用Object.assign和擴展運算符等簡單方式實現,深拷貝則需要使用遞歸、JSON.parse & JSON.stringify或者Lodash庫等方式實現。

原創文章,作者:小藍,如若轉載,請註明出處:https://www.506064.com/zh-hk/n/236320.html

(0)
打賞 微信掃一掃 微信掃一掃 支付寶掃一掃 支付寶掃一掃
小藍的頭像小藍
上一篇 2024-12-12 11:59
下一篇 2024-12-12 11:59

相關推薦

  • at least one option must be selected

    問題解答:當我們需要用戶在一系列選項中選擇至少一項時,我們需要對用戶進行限制,即「at least one option must be selected」(至少選擇一項)。 一、…

    編程 2025-04-29
  • Python列表中負數的個數

    Python列表是一個有序的集合,可以存儲多個不同類型的元素。而負數是指小於0的整數。在Python列表中,我們想要找到負數的個數,可以通過以下幾個方面進行實現。 一、使用循環遍歷…

    編程 2025-04-29
  • Python周杰倫代碼用法介紹

    本文將從多個方面對Python周杰倫代碼進行詳細的闡述。 一、代碼介紹 from urllib.request import urlopen from bs4 import Bea…

    編程 2025-04-29
  • JS Proxy(array)用法介紹

    JS Proxy(array)可以說是ES6中非常重要的一個特性,它可以代理一個數組,監聽數據變化並進行攔截、處理。在實際開發中,使用Proxy(array)可以方便地實現數據的監…

    編程 2025-04-29
  • java client.getacsresponse 編譯報錯解決方法

    java client.getacsresponse 編譯報錯是Java編程過程中常見的錯誤,常見的原因是代碼的語法錯誤、類庫依賴問題和編譯環境的配置問題。下面將從多個方面進行分析…

    編程 2025-04-29
  • 金額選擇性序列化

    本文將從多個方面對金額選擇性序列化進行詳細闡述,包括其定義、使用場景、實現方法等。 一、定義 金額選擇性序列化指根據傳入的金額值,選擇是否進行序列化,以達到減少數據傳輸的目的。在實…

    編程 2025-04-29
  • Python中引入上一級目錄中函數

    Python中經常需要調用其他文件夾中的模塊或函數,其中一個常見的操作是引入上一級目錄中的函數。在此,我們將從多個角度詳細解釋如何在Python中引入上一級目錄的函數。 一、加入環…

    編程 2025-04-29
  • 英語年齡用連字符號(Hyphenation for English Age)

    英語年齡通常使用連字符號表示,比如 “five-year-old boy”。本文將從多個方面探討英語年齡的連字符使用問題。 一、英語年齡的表達方式 英語中表…

    編程 2025-04-29
  • Python官網中文版:解決你的編程問題

    Python是一種高級編程語言,它可以用於Web開發、科學計算、人工智能等領域。Python官網中文版提供了全面的資源和教程,可以幫助你入門學習和進一步提高編程技能。 一、Pyth…

    編程 2025-04-29
  • Idea新建文件夾沒有java class的解決方法

    如果你在Idea中新建了一個文件夾,卻沒有Java Class,應該如何解決呢?下面從多個方面來進行解答。 一、檢查Idea設置 首先,我們應該檢查Idea的設置是否正確。打開Id…

    編程 2025-04-29

發表回復

登錄後才能評論