淺談js中的深淺拷貝

談深淺拷貝以前咱們先來聊一聊對象javascript

什麼是對象?html

對象用來存儲鍵值對和更復雜的實體,能夠經過花括號 {…} 和其中包含一些可選的屬性來建立。屬性是一個鍵值對,鍵是一個字符串(也叫作屬性名),值能夠是任何類型。java

對象和其餘原始的類型相比有一個很重要的區別,對象都是按引用存儲複製的。git

  

let user = { name: 'John' };

let admin = user;

admin.name = 'Pete'; //  改變 "admin" 的引用

alert(user.name); // 'Pete', changes are seen from the "user" reference

上面的例子展現了只存在一個對象,就像咱們的一個抽屜帶有兩把鑰匙,若是一個鑰匙(admin)去使用了抽屜,稍後使用另一個鑰匙(user)打開的時候,就會看到有變化。github

複製一個對象的變量也等同於建立了此對象的另外一個引用。算法

那麼咱們該怎麼複製一個對象呢?建立一份獨立的拷貝,一份複製?code

這也是可行的,可是有一點麻煩,由於JS並無原生的方法支持這麼作。實際上,咱們不多這麼作。複製引用不少時候是好用的。htm

若是咱們真的想這麼作,就須要建立一個新的對象,遍歷現有對象的屬性,在原始值的狀態下複製給新的對象。對象

像這樣:blog

let user = {
  name: "John",
  age: 30
};

let clone = {}; // 新的空對象

// 複製全部的屬性值
for (let key in user) {
  clone[key] = user[key];
}

// 如今複製是獨立的複製了
clone.name = "Pete"; // 改變它的值

alert( user.name ); // 原對象屬性值不變

  

咱們也能夠用Object.assign 來實現。

像這樣:

let user = {
  name: "John",
  age: 30
};

let clone = Object.assign({}, user);

  

它複製了 user 對象全部的屬性給了一個空對象,而後返回拷貝後的對象。事實上,這跟循環賦值同樣,可是更短。

直到如今,咱們是假設全部的 user 屬性都是原始值,可是若是對象屬性指向對象呢?

像這樣:

let user = {
  name: "John",
  sizes: {
    height: 182,
    width: 50
  }
};

let clone = Object.assign({}, user);

alert( user.sizes === clone.sizes ); // true,同一個對象

// user 和 clone 共享 sizes 對象
user.sizes.width++;       // 在這裏改變一個屬性的值
alert(clone.sizes.width); // 51,在這裏查看屬性的值

這個叫淺拷貝,爲了解決上面的的問題,咱們在複製的時候應該檢查 user[key] 的每個值,若是是一個對象,咱們再複製一遍這個對象,這叫作深拷貝。

有一個標準的深拷貝算法,解決上面和一些更復雜的狀況,叫作 Structured cloning algorithm。爲了避免重複造輪子,咱們使用它的一個 JS 實現的庫 lodash, 方法名叫作 _.cloneDeep(obj)

相關文章
相關標籤/搜索