JavaScript的深淺複製

来源:https://www.cnblogs.com/zoiyin/archive/2019/11/02/js_copy.html
-Advertisement-
Play Games

JavaScript的深淺複製 為什麼有深複製、淺複製? JavaScript中有兩種數據類型,基本數據類型如 、`null boolean number string Object`。簡單數據類型只存儲在記憶體中的 棧區 ,複製的時候是值傳遞給新的索引。而複雜數據類型由棧區和 堆區 共同儲存,棧區執 ...


JavaScript的深淺複製

為什麼有深複製、淺複製?

JavaScript中有兩種數據類型,基本數據類型如undefinednullbooleannumberstring,另一類是Object。簡單數據類型只存儲在記憶體中的棧區,複製的時候是值傳遞給新的索引。而複雜數據類型由棧區和堆區共同儲存,棧區執行同樣的操作,只是把堆地址複製了一份,而真實數據在堆區中依然只有一份。
為了不影響原有數據,那麼我們就新建一個對象,遍歷原有對象的屬性賦值到新屬性。

let newObj = {}
for (let prop in obj) {
  newObj[prop] = obj[prop]
}

上面這個迴圈也可以用Object.assign({}, obj);來實現。
這樣做是否解決問題?未必,因為Object中可以嵌套Object,如果原有對象屬性中有複雜數據類型,那麼新的對象中也只能得到一個地址。這種情況被稱為淺複製。我們希望能將對象中的對象,無論多少層,都能複製一份,能達到這種效果的,稱為深複製

深複製的幾種方法

首先假設有數據

let obj = {
    a: 23,
    b: [0, 1, [2, 3], function() {console.log('in array')}, undefined],
    c: {k: 'value'},
    d: function() {console.log('a')}
    }

JSON.parse(JSON.stringify(obj))

let newObj = JSON.parse(JSON.stringify(obj))
newObj.newKey = 'newValue'
console.log(obj)
console.log(newObj)

如果處理對象只是簡單的鍵值對,這個方法效果不錯。

這個方法的缺點

  • 無法複製函數
  • 忽略undefined
  • 無法處理Set、Map、Symbol類型(即使用上repalce參數)
  • 原有的原型鏈會消失
  • 迴圈引用的對象會報錯

    遞歸法

    因為要處理屬性的值也是Object這種情況,自然可以想到遞歸這種處理方法。
function deepCopy(oldObj, newObj) {
    let obj = newObj || {} 
    for (let i in oldObj) {
        if (oldObj[i] === obj) { // 防止迴圈引用
            continue
        }

        if (typeof oldObj[i] === 'object') {
            // obj[i] = (oldObj[i].constructor === Array) ? [] : {}
            obj[i] = oldObj[i] instanceof Array ? [] : {}
            deepCopy(oldObj[i], obj[i])
        } else {
            obj[i] = oldObj[i]
        }
    }
    return obj;
}

這樣就能處理一個嵌套了Object和Array等複雜變數的對象。但是對象中還可能包含Date和RegExp對象、Set、Map……

Lodash庫

const lodash = require('lodash')
let newObj = lodash.cloneDeep(obj)

數組的複製

let arr = [1, 2, 3, [4, 5], {a: 1}]

let copy = arr
copy.push(6)

let copy1 = [...arr]
copy1.push(999)

let copy2 = Array.from(arr)
copy2.push(888)

let copy3 = arr.slice()
copy3.push(777)

// 以上方法都是淺拷貝
arr[4].a = 2

console.log(arr)   // [ 1, 2, 3, [ 4, 5 ], { a: 2 }, 6 ]
console.log(copy1) // [ 1, 2, 3, [ 4, 5 ], { a: 2 }, 6 ]
console.log(copy2) // [ 1, 2, 3, [ 4, 5 ], { a: 2 }, 6, 888 ]
console.log(copy3) // [ 1, 2, 3, [ 4, 5 ], { a: 2 }, 6, 777 ]

參考連接

  1. 摸索 JS 內深拷貝的最佳實踐 - 簡單易懂的前端角 - SegmentFault 思否
  2. 理解JavaScript:不可變的原始值與可變的對象引用
  3. [ JS 進階 ] 基本類型 引用類型 簡單賦值 對象引用 - kraaas前端博客 - SegmentFault 思否
  4. 什麼是js深拷貝和淺拷貝及其實現方式
  5. js 深拷貝 vs 淺拷貝 - 掘金
  6. 深拷貝的終極探索(99%的人都不知道) - 顏海鏡 - SegmentFault 思否

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 關於理財,第一個環節就是進行記賬,去找出自己的開支清單。 用清單可以梳理出來哪些該花,哪些應該省下來,然後給自己做一些計劃,進行積累原始資金。 我剛開始記了一月,發現確實把我的花銷能清晰的記錄下來,讓我看清我的每一筆開銷,然後我就開始去想著什麼可以省下來。 把網費降了一些,把交通從打車換成公交,然後 ...
  • 一、設計網頁的思想 拿到需求之後我們先對各個模塊(盒子)進行劃分,然後從外到內進行設計(1)設計一個盒子最基本的設計大致包括背景顏色(其實用於識別),寬,高,邊界浮動流還是標準流. (2)然後盒子和盒子之間的外邊距margin (3)然後在進入到小盒子中,進一步劃分盒子,這樣再重覆第一二步 註意點: ...
  • CSS的元素顯示模式 1. 什麼是元素顯示模式 作用:網頁的標簽非常多,在不同的地方會用到不同類型的標簽,瞭解他們的特點可以更好的佈局我們的網頁 元素的顯示模式就是元素(標簽)以什麼樣的方式進行顯示,比如 自己獨占一行,比如一行可以放多個 HTML元素一般分為塊元素和行內元素兩種類型 2. 塊元素 ...
  • 品牌管理 分析 1. 獲取到 id 和 name ,直接從 data 上面獲取 2. 組織出一個對象 3. 把這個對象,調用 數組的 相關方法,添加到 當前 data 上的 list 中 4. 註意:在Vue中,已經實現了數據的雙向綁定,每當我們修改了 data 中的數據,Vue會預設監聽到數據的改 ...
  • vue組件是什麼: 組件是可復用的 Vue 實例,組件可以進行任意次數的復用 vue組件創建方式有3種: 組件的da'ta必須作為一個函數,返回對象 ...
  • python day 21 2019/11/02 [TOC] 學習資料來自老男孩與尚學堂 1. HTML 1.1 常見的HTML元素 1. HTML的作用:定義整個頁面"長"成什麼樣,相當於網站的骨架。 2. HTML搭骨架的標簽: 2.1. 標題標簽: h1~h6 2.2. 容器標簽: div : ...
  • var str = 'fdhfgcsaedvcfhgfh'; var index = str.indexOf('f'); // 字元出現的位置 var num = 0; // 這個字元出現的次數 while(index !== -1) { console.log(index); // 列印字元串出現 ...
  • 用時間戳來計算倒計時 時間戳:當前時間距離1970年1月1日一共過了多少毫秒。 得到當前時間以及結束時間的時間戳,二者相減即是剩餘的毫秒數,將剩餘毫秒數轉化成 時 分 秒 即是倒計時。 function countDown(Time) { var nowTime = +new Date(); //當 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...