在 JavaScript 中如何克隆對象?

做者:Luigi Nori
譯者:前端小智
來源:stackabuse

有夢想,有乾貨,微信搜索 【大遷世界】 關注這個在凌晨還在刷碗的刷碗智。javascript

本文 GitHub https://github.com/qq449245884/xiaozhi 已收錄,有一線大廠面試完整考點、資料以及個人系列文章。前端

當咱們想要複製原始值和引用值(對象)時,它們的行爲會大不相同。java

原始值

咱們假設一個變量 name 具備一個與之關聯的原始值(number,string,boolean,undefined 和null)。 若是咱們將此變量 name 複製到另外一個變量name2 ,則原始變量的任何修改都不會影響到第二個變量,由於它們是原始值。git

let name="前端小智";
let name2= name;
console.log (name, name2); // 前端小智, 前端小智
name="王大冶";
console.log (name,name2); // 王大冶 前端小智

引用值

可是,若是咱們對引用類型的值進行相同的操做,則咱們對一個變量所作的任何更改也將反映在另外一個變量中,由於兩個變量都指向同一對象。github

數組

要拷貝數組,slice()方法用於建立數組的新副本。 能夠獨立修改此副本,而不會影響原始數組。面試

若是未傳遞任何參數,則它會精確複製數組,但數字也能夠做爲參數傳遞。 若是僅傳遞一個數字,它將肯定咱們要從其進行復制的索引的值,而若是傳遞兩個數字,則將標記開始和結束。數組

// 示例1
const names = ['前端小智', '王大冶', '小力'];
const names2 = names;
console.log(names, names2);
// ["前端小智", "王大冶", "小力"] 
// ["前端小智", "王大冶", "小力"] 

// 示例2
names2[2] = '前端小力';
console.log(names, names2);
//  ["前端小智", "王大冶", "前端小力"] 
//  ["前端小智", "王大冶", "前端小力"] 

// 示例3
const name2 = names.slice();
names[2] = '我是隔壁老智';
console.log(name2, names2)
// ["前端小智", "王大冶", "前端小力"]
//  ["前端小智", "王大冶", "我是隔壁老智"]

對象

當引用值是一個對象時,也會發生一樣的狀況,對其屬性之一的任何修改都會影響這兩個變量。 若要克隆對象,請使用 Object.assign() 方法,該方法會將一個或多個源對象的全部可枚舉屬性的值複製到目標對象,可是此方法僅對對象的一個淺拷貝。微信

// 示例1
const names = {
  name: '前端小智',
  surname: '隔壁老智'
}

const names2 = names;
console.log(names, names2) // 打印結果是如出一轍的

// 示例2
names2.surname ='隔壁老王';
console.log(names, names2)

// {name: "前端小智", surname: "隔壁老王"}
// {name: "前端小智", surname: "隔壁老王"}

// 示例3
const names3 = Object.assign({}, names);
names3.surname = '隔壁老色P';
console.log(names, names3)

// {name: "前端小智", surname: "隔壁老王"}
// {name: "前端小智", surname: "隔壁老色P"}

要對對象進行深拷貝,須要使用其餘方法。函數

正如咱們所說,Object.assign()方法只是一個淺拷貝(即,當咱們的對象沒有其餘對象做爲屬性時)纔有效。 在這些狀況下,必須對對象進行深拷貝。工具

與淺拷貝不一樣,深拷貝以遞歸方式複製每一個子對象,直到全部涉及的對象都被複製爲止。

咱們可使用什麼方法複製對象的深層副本?

JSON.parse(JSON.stringify(obj))

此方法使用JSON.stringify()將對象轉換爲字符串,而後再用JSON.parse()將其轉換回對象。 此方法對簡單對象有效,但若是對象屬性是函數時無效。

const names = {
  name: '前端小智',
  surname: '隔壁老智',
  social: {
    wx: '大遷世界',
    url: 'www.lsp.com'
  }
}
const names2 = JSON.parse(JSON.stringify(names));
names2.social.url = 'www.baidu.com';
console.log(names, names2);

/** 
{
  name: "前端小智"
  social: {wx: "大遷世界", url: "www.lsp.com"}
  surname: "隔壁老智"
}
*/

/** 
{
  name: "前端小智"
  social: {wx: "大遷世界", url: "www.baidu.com"}
  surname: "隔壁老智"
}
*/

深度拷貝

另外一種很是有趣和優雅的對象深度複製方法是使用遞歸函數。

咱們建立了一個deepClone(object)函數,將想要克隆的對象做爲參數傳遞給它。在函數內部,將建立一個局部變量克隆,這是一個空對象,其中將從起始對象克隆的每一個屬性都將添加到該對象中。

具體思路:

  • 若是該屬性不是對象,則將其簡單地克隆並添加到新的克隆對象中。
  • 若是屬性是對象,則再次執行deepClone(value)函數,並將屬性的值(在這種狀況下爲對象)做爲參數傳遞,並重復相同的過程。
function deepClone(object) {
  var clone = {};
  for (var key in object) {
    var value = object[key];
    if (typeof(value) !== 'object') {
      clone[key] = value;
    } else {
      clone[key]=deepClone(value);
    }
  }
  return clone;
} 

deepClone({value1:1,value2:{value3:2}});
//{value1:1,value2:{value3:2}}
deepClone({value1:1,value2:{value3:{value3b:3}}});
//{value1:1,value2:{value3:{value3b:3}}}

代碼部署後可能存在的BUG無法實時知道,過後爲了解決這些BUG,花了大量的時間進行log 調試,這邊順便給你們推薦一個好用的BUG監控工具 Fundebug

原文:https://www.ma-o.org/en/progr...

交流

有夢想,有乾貨,微信搜索 【大遷世界】 關注這個在凌晨還在刷碗的刷碗智。

本文 GitHub https://github.com/qq44924588... 已收錄,有一線大廠面試完整考點、資料以及個人系列文章。

相關文章
相關標籤/搜索