JavaScript >> Javascript 文檔 >  >> Tags >> object

在 JavaScript 中克隆對象的 4 種方法

由於 JavaScript 對像是引用類型,所以不能只使用等號運算符 (= ) 來複製一個對象。在 JavaScript 中創建對象時,其值為 not 分配給變量的目錄。相反,該變量只保存對該值的引用。

什麼是引用類型?

讓我們看下面的例子來了解reference 類型表示:

const obj1 = { mango: '🥭️', apple: '🍎' };

const obj2 = obj1;

console.log(
    obj1, // { mango: '🥭️', apple: '🍎' }
    obj2  // { mango: '🥭️', apple: '🍎' }
);

正如您在上面看到的,我創建了一個對象,然後使用 = 將其分配給一個新變量 操作員。兩個對像都輸出相同的鍵值對。到目前為止,一切順利!

現在讓我們為第一個對象添加一個新鍵,看看會發生什麼:

obj1.lemon = '🍋';

console.log(
    obj1, // { mango: '🥭️', apple: '🍎', lemon: '🍋' } ✅
    obj2  // { mango: '🥭️', apple: '🍎', lemon: '🍋' } ❌
);

您可以看到我只對 obj1 進行了更改 但它影響了obj2 也是。這不是我們在復制對象時所期望的。這是因為對像是引用類型,當我們使用 = , 它只有 將指針複製到分配給對象的內存而不是實際值。

淺克隆與深克隆

淺克隆 只複製對像中可用的原始類型,如字符串、數字和布爾值。任何嵌套對像或數組都不會被遞歸複製。相反,只有對該對象的引用被複製到新對象。這意味著原始對象和復制對像都繼續引用同一個嵌套對象。

如果原始對象引用其他外部對象,則在創建對象的淺表副本時也不會遞歸複製它們。只複製對外部對象的引用。

另一方面,深度克隆 遞歸複製所有內容:原始數據類型、嵌套和外部對象、數組、函數、日期等。克隆的對象完全獨立於原始對象。

JavaScript 提供了許多方法來創建對象的淺層和深層克隆。您可以使用擴展運算符 (... ) 和 Object.assign() 快速創建淺對象副本的方法。對於對象的深度克隆,您可以編寫自己的自定義函數,也可以使用 Lodash 等第三方庫。

Object.assign() 方法

創建對象淺拷貝的最簡單快捷的方法是使用 ES6 的 Object.assign(target, source1, soure2, ...) 方法。該方法將一個或多個源對象的所有可枚舉自身屬性複製到目標對象,並返回目標對象:

const fruits = { mango: '🥭️', apple: '🍎' };

const moreFruits = Object.assign({}, fruits);

console.log(moreFruits);
// { mango: '🥭️', apple: '🍎' }

注意空的 {} 源對像作為第一個參數。這是確保原始對像不被更改所必需的。這種方式對IE等老瀏覽器缺乏支持,只適用於現代瀏覽器。

查看本指南以了解有關 Object.assign() 的更多信息 方法。

擴展運算符

擴展運算符 (... ) 是另一個 ES6 特性,它提供了一種簡單的方法來執行對象的淺層克隆,相當於 Object.assign() 確實:

const fruits = { mango: '🥭️', apple: '🍎' };

const moreFruits = { ...fruits };

console.log(moreFruits);
// { mango: '🥭️', apple: '🍎' }

儘管傳播運算符自 ES6(ESMAScript 2015)以來就存在,但對克隆對象的支持直到最近才在 ES9(ESMAScript 2018)中引入。所以你應該只考慮將這種方法用於最新版本的現代瀏覽器。

JSON 方法

如果您的對象僅包含原始類型,並且不包含嵌套或外部對象、數組、Date 對象、函數等,您可以使用 JSON 方法輕鬆創建對象的深層克隆:JSON.stringify()JSON.parse()

const fruits = { mango: '🥭️', apple: '🍎' };

const moreFruits = JSON.parse(JSON.stringify(fruits));

console.log(moreFruits);
// { mango: '🥭️', apple: '🍎' }

這種方法適用於所有現代瀏覽器和 IE8+。但是,有兩個缺點:

  • 對象必須與 JSON 格式兼容。這意味著嵌套對象必須是 JSON 可序列化和可反序列化的。
  • 當對象包含大量屬性時,它比其他解決方案慢。

JSON 方法僅支持沒有函數和符號屬性的字符串、數字和對象文字。當對象包含不兼容的值時,您會看到一種奇怪的行為:

// undefined is omitted
// Infinity is turned to null
JSON.parse(JSON.stringify({ a: undefined, b: Infinity })); 

// { b: null }

// Date object is turned to string
JSON.parse(JSON.stringify({ a: new Date() })); 

// { a: "2020-06-16T19:44:57.492Z" }

// function is omitted too
JSON.parse(JSON.stringify({ a: () => { return 'Hi'; } })); 

// {}

你應該 將此方法用於 JSON 兼容對象。對於包含 JSON 不兼容值的對象,請考慮使用 Lodash 之類的第 3 方庫來創建深度克隆。

Lodash 的 cloneDeep() 方法

Lodash 提供了 cloneDeep() 遞歸地將原始對像中的所有內容複製到新對象的方法。它適用於所有數據類型,包括函數、嵌套對象、數組和符號。

這是一個例子:

const _ = require('lodash');

const obj = {
    name: 'John Doe',
    age: 45,
    address: {
        city: 'Berlin',
        country: 'DE'
    },
    job: undefined,
    credits: Infinity
};

const cloned = _.cloneDeep(obj);

console.log(cloned);

// {
//     name: 'John Doe',
//     age: 45,
//     address: { city: 'Berlin', country: 'DE' },
//     job: undefined
//     credits: Infinity
// }

要了解有關 JavaScript 對象、原型和類的更多信息,請查看這篇文章。

閱讀下一篇: 如何在 JavaScript 中復制數組


Tutorial JavaScript 教程
  1. 執行使用 .innerHTML 插入的 <script> 元素

  2. 5 分鐘內的 HTTP 狀態碼

  3. 有多少 UI 庫太多了?

  4. 可以在 ReactJS 中的錨標記上調用 onClick

  5. #7 - 最近和最小的 CodeWars Kata (5 kyu)

  6. 終於了解工廠設計模式

  7. 我用 `console.log()` 檢查了這個和 React 基礎知識

  1. NestJs:確保你的班級用合適的裝飾器裝飾

  2. 一步一步學習 ReasonReact 部分:2

  3. ES6 深度挑戰

  4. JavaScript 中的所有數據類型

  5. JavaScript Basic - this、閉包、Math.random()、DOM...

  6. 可選鏈接已經到來!

  7. 部署站點時CKEditor不工作(PHP)

  1. 2022 年,不要使用 console.log(😎)

  2. Angular 聊天應用教程

  3. 全屏移動模式。它能有多難?

  4. 將 Scratch 從 Flash 移植到 JavaScript:性能、互操作性和擴展