首頁  >  問答  >  主體

javascript - 引用物件賦值 深淺拷貝 jquery.extend

引用型別賦值給另一個引用型別,它們只是都是指向的同一個位址,操作間會互相影響。
深拷貝,就是重新分配空間,讓它跟著之前的物件或陣列不受影響。
淺拷貝就是等同於引用型別的賦值。

var a={banner:{size:1,weight:'0.5kg'}};
var b={apple:{size:1},banner:{size:3}};
$.extend(true,a,b)=>{banner:{size:3,weight:'0.5kg'},apple:{size:1}};
$.extend(a,b)=>{banner:{size:3},apple:{size:1}};

我看過jquery源碼,深拷貝是要進行遞歸的。
但是我不理解,跟互相影響有什麼關係,還是說我上面的概念理解錯誤

PHPzPHPz2734 天前971

全部回覆(2)我來回復

  • 给我你的怀抱

    给我你的怀抱2017-05-19 10:35:54

    淺拷貝

    僅對object頂層鍵進行遍歷和重新賦值(給對應的引用),例如:

    var a = {
      x: {
        name: 'x',
        value: 10,
      },
      y: 10,
      o: {},
    }
    var b = {
      x: {
        name: 'x2',
        value: 20,
      },
      y: {
        name: 'y2',
        value: 20,
      },
      z: {}
    }
    $.extend(a, b)

    這個過程裡面,從b中取出所有頂層元素,即b.x, b.y, b.z,然後將它們一一賦值給a對應的鍵,所以最後a就有了新的a.x, a.y, a.z,同時,a.o還保留在a中,這時a.x === b.x, a.y === b.y, a.z === b.z,因為它們都是指向同一個物件的引用。既然是引用,當你操作a.x的時候,例如a.x.name = 'x3',那麼b.x.name也變成了'x3'。

    深拷貝

    深拷貝將深入物件元素的末層進行重新賦值,而非引用。就拿上面的a,b舉例,執行:

    $.extend(true, a, b)

    將會深入b內部進行遍歷,拿每一個節點的值與a對應(一模一樣)的節點進行比較,如果不同則為a開闢儲存空間,把值賦進去,如果a不存在這個節點,就為它創建後賦值進去。 a的第一層子節點跟b第一層不存在相等關係,連==都不成立。

    深拷貝後,a原有的一些節點會保留下來,b給過去的節點會覆蓋或增加,但是和b之間不存在任何引用關係,所以修改a的任何一個節點,都不會影響b。這在一些數據處理的時候非常有用,為了不影響原始數據,需要在處理數據之前深拷貝一份再進行處理。

    深拷貝的時候,陣列的索引號碼被當作鍵名對待,所以陣列元素會被修改,而不是被加入到原始資料中。如:

    var a = [
      {
        x: 1,
      }, 
      {
        x: 2,
      },
    ]
    var b = [
      {
        y: 2
      },
    ]
    $.extend(true, a, b) 

    將會得到:

    var a = [
      {
        x: 1,
        y: 2
      }, 
      {
        x: 2,
      },
    ]

    b的第一個原始被合併到a的第一個元素裡面去了,這個合併是因為數組按照元素的索引號作為鍵來操作。所以,合併數組不能用extend,而應該考慮用merge或concat。

    回覆
    0
  • 滿天的星座

    滿天的星座2017-05-19 10:35:54

    只是名字重複了,和深拷貝/淺拷貝沒有關係。應該叫遞歸拷貝比較合適。

    回覆
    0
  • 取消回覆