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

了解如何以三種不同的方式在 JavaScript 中克隆對象。本文將向您展示如何使用 Object.assign() 方法、JSON.parse() 方法和 Spread 運算符來克隆對象。

JavaScript 對像是鍵值對的集合。它是一種非原始數據類型,可以包含各種數據類型。例如:

const userDetails = {
  name: "John Doe",
  age: 14,
  verified: false
};

在 JavaScript 中使用對象時,您有時可能想要更改值或向對象添加新屬性。

在某些情況下,在更新或添加新屬性之前,您需要創建一個新對象並複製或克隆原始對象的值。

例如,如果您想複製userDetails對象的值,然後將名稱更改為不同的名稱。在典型意義上,您將需要使用等於 (=) 運算符。

const newUser = userDetails;
console.log(newUser); // {name: 'John Doe', age: 14, verified: false}

一切似乎仍然很好,但讓我們看看如果我們編輯第二個對象會發生什麼:

const newUser = userDetails;
newUser.name = "Jane Doe";

console.log(newUser); // {name: 'Jane Doe', age: 14, verified: false}

新對像一切都很好,但如果您嘗試檢查原始對象的值,您會注意到它受到了影響。為什麼?如何?

console.log(userDetails); // {name: 'Jane Doe', age: 14, verified: false}

這就是問題所在。原始對象會受到影響,因為對像是引用類型。這意味著您存儲在克隆對像或原始對像中的任何值都指向同一對象。

這不是你想要的。您希望將對象的值存儲在新對像中,並在不影響原始數組的情況下操作新對像中的值。

在本文中,您將學習可用於執行此操作的三種方法。您還將了解深克隆和淺克隆的含義以及它們的工作原理。

如果您很著急,以下是這三種方法及其工作原理的示例。

// Spread Method
let clone = { ...userDetails }

// Object.assign() Method
let clone = Object.assign({}, userDetails)

// JSON.parse() Method
let clone = JSON.parse(JSON.stringify(userDetails))

如果您不著急,我們就開始吧。

如何使用 Spread 運算符在 JavaScript 中克隆對象

擴展運算符是在 ES6 中引入的,可以將值擴展到前面有三個點的對像中。

// Declaring Object
const userDetails = {
  name: "John Doe",
  age: 14,
  verified: false
};

// Cloning the Object with Spread Operator
let cloneUser = { ...userDetails };

console.log(cloneUser); // {name: 'John Doe', age: 14, verified: false}

這不再被引用,這意味著更改對象的值不會影響原始對象。

// Cloning the Object with Spread Operator
let cloneUser = { ...userDetails };

// changing the value of cloneUser
cloneUser.name = "Jane Doe"

console.log(cloneUser.name); // 'Jane Doe'
console.log(cloneUser); // {name: 'Jane Doe', age: 14, verified: false}

當您檢查原始對像或整個對像中的名稱值時,您會發現它不受影響。

console.log(userDetails.name); // 'John Doe'
console.log(userDetails); // {name: 'John Doe', age: 14, verified: false}

注意:當引用更深的對象時,只能使用展開語法來製作對象的淺表副本。當我們讀到本文的最後一部分時,您就會明白。

如何在 JavaScript 中克隆對象Object.assign()

擴展運算符的替代方法是Object.assign()方法。您可以使用此方法將值和屬性從一個或多個源對象複製到目標對象。

// Declaring Object
const userDetails = {
  name: "John Doe",
  age: 14,
  verified: false
};

// Cloning the Object with Object.assign() Method
let cloneUser = Object.assign({}, userDetails);

console.log(cloneUser); // {name: 'John Doe', age: 14, verified: false}

這不再被引用,這意味著更改對象的值不會影響原始對象。

// Cloning the Object with Object.assign() Method
let cloneUser = Object.assign({}, userDetails);

// changing the value of cloneUser
cloneUser.name = "Jane Doe"

console.log(cloneUser.name); // 'Jane Doe'
console.log(cloneUser); // {name: 'Jane Doe', age: 14, verified: false}

當您檢查原始對像或整個對像中的名稱值時,您會發現它不受影響。

console.log(userDetails.name); // 'John Doe'
console.log(userDetails); // {name: 'John Doe', age: 14, verified: false}

注意:Object.assign()當引用更深的對象時,只能使用該方法來製作對象的淺表副本。當我們讀到本文的最後一部分時,您就會明白。

如何克隆對象JSON.parse()

最後一個方法是 JSON.parse()。您將同時使用此方法JSON.stringify()。您可以使用它來深度克隆,但它有一些缺點。首先,讓我們看看它是如何工作的。

// Declaring Object
const userDetails = {
  name: "John Doe",
  age: 14,
  verified: false
};

// Cloning the Object with JSON.parse() Method
let cloneUser = JSON.parse(JSON.stringify(userDetails));

console.log(cloneUser); // {name: 'John Doe', age: 14, verified: false}

另外,與之前的方法一樣,不再引用此方法。這意味著您可以更改新對像中的值而不影響原始對象。

// Cloning the Object with JSON.parse() Method
let cloneUser = JSON.parse(JSON.stringify(userDetails));

// changing the value of cloneUser
cloneUser.name = "Jane Doe"

console.log(cloneUser.name); // 'Jane Doe'
console.log(cloneUser); // {name: 'Jane Doe', age: 14, verified: false}

當您檢查原始對像或整個對像中的名稱值時,您會發現它不受影響。

console.log(userDetails.name); // 'John Doe'
console.log(userDetails); // {name: 'John Doe', age: 14, verified: false}

注意:此方法可用於深度克隆,但不是最佳選擇,因為它不適用於functionsymbol屬性。

現在讓我們探討淺克隆和深克隆以及如何使用該JSON.parse()方法執行深克隆。您還將了解為什麼它不是最佳選擇。

淺克隆與深克隆

到目前為止,本文使用的示例是只有一個級別的基本對象。這意味著我們只執行了淺克隆。但是,當一個對象具有多個級別時,您將需要執行深度克隆。

// Shallow object
const userDetails = {
  name: "John Doe",
  age: 14,
  verified: false
};

// Deep object
const userDetails = {
  name: "John Doe",
  age: 14,
  status: {
    verified: false,
  }
};

請注意,深層對象具有多個級別,因為該對userDetails像中還有另一個對象。一個深層對象可以有任意多個層次。

注意:當您使用展開運算符或Object.assign()方法克隆深層對象時,將引用更深的對象。

const userDetails = {
  name: "John Doe",
  age: 14,
  status: {
    verified: false
  }
};

// Cloning the Object with Spread Operator
let cloneUser = { ...userDetails };

// Changing the value of cloneUser
cloneUser.status.verified = true;

console.log(cloneUser); // {name: 'John Doe', age: 14, status: {verified: true}}
console.log(userDetails); // {name: 'John Doe', age: 14, status: {verified: true}}

您會注意到原始對象和新對像都會受到影響,因為當您使用擴展運算符或Object.assign()方法來克隆深層對象時,將引用更深的對象。

如何解決這個問題

您可以使用該JSON.parse()方法,一切都會正常。

const userDetails = {
  name: "John Doe",
  age: 14,
  status: {
    verified: false
  }
};

// Cloning the Object with Spread Operator
let cloneUser = JSON.parse(JSON.stringify(userDetails));

// Changing the value of cloneUser
cloneUser.status.verified = true;

console.log(cloneUser); // {name: 'John Doe', age: 14, status: {verified: true}}
console.log(userDetails); // {name: 'John Doe', age: 14, status: {verified: false}}

但這種方法有一個問題。問題是您可能會丟失數據。如何?

JSON.stringify()可以很好地處理數字、字符串或布爾值等基本數據類型,這就是您在前面的示例中看到的。但有時,JSON.stringify()如果您不了解某些值及其處理方式,則結果是不可預測的。

例如,它不適用於函數、符號或undefined值。它還會將其他值更改為Nan和,Infinity從而null破壞您的代碼。當你有一個函數、符號或未定義的值時,它將返回一個空的鍵值對並跳過它。

const userDetails = {
  name: "John Doe",
  age: 14,
  status: {
    verified: false,
    method: Symbol(),
    title: undefined
  }
};

// Cloning the Object with Spread Operator
let cloneUser = JSON.parse(JSON.stringify(userDetails));

一切似乎都工作正常,但對於新對象,JSON.stringify()將不會返回未定義和符號值的鍵值對。

console.log(cloneUser); 

// Output
{
  name: "John Doe",
  age: 14,
  status: {
    verified: false
  }
};

這意味著你需要小心。實現深度克隆的最佳選擇是使用Lodash。然後您可以確保您的任何數據都不會丟失。

const userDetails = {
  name: "John Doe",
  age: 14,
  status: {
    verified: false,
    method: Symbol(),
    title: undefined
  }
};

console.log(_.cloneDeep(userDetails));

包起來!

本文教您如何使用三種主要方法在 JavaScript 中克隆對象。您已經了解了這些方法的工作原理以及何時使用每種方法。您還了解了深度克隆。

祝你編碼愉快!

來源: https: //www.freecodecamp.org

#javascript

1.00 GEEK