物件的繼承(三)--複製屬性的第二種方法

物件的繼承(三)--複製屬性的第二種方法:

上回說到物件的繼承(二)--複製屬性的第一種方法,這次繼續說說另外一種複製屬性的方式。這方式其實很簡單,其實就是直接用迴圈將物件的屬性複製一份而已。感覺這方法笨笨的,但其實這種繼承方式還蠻廣為使用的。

程式碼如下(c繼承p的屬性 ):

function copy(p,c){
  var i;
  c=c||{}; //如果c不存在 就建立一個空物件
  for ( i in p){
    if(p.hasOwnProperty(i)){ //判斷屬性是否屬於p本身,而不是從原型練繼承下來的屬性
      c[i]=p[i];//將p的屬性複製到c中
    }
  }
  return c;//傳回複製完後的物件
}

這方法其實不錯用,只要簡單的呼叫copy()函式就能輕鬆地將某個物件的屬性複製到另一個物件中。不過要注意的是,Javascript在複製物件或是陣列時,會有一種淺層複製(shallow copy)的慣例。所謂的淺層複製意思就是說,對於物件與陣列而言,只有參考被複製。換個話說就是如果p[i]是指向某個物件或是陣列,那 c[i]=p[i] 其實也就是把參考複製過去而已,所以改變c[i]指向物件的同時,p[i]指向的物件也會跟著改變,因為p[i]與c[i]其實是指向同一個物件。(這裡的物件指的是它的型態是object,而不是string, number, 等等基本型態..)。

有時候我們需要將物件與陣列都進行深層複製,此時就需要將物件內的每個屬性都一個一個複製過去,這時候使用遞迴來進行複製或許是個不錯的選擇。整個概念就是,當遇到物件或陣列屬性時,在子物件(程式碼中的c)中建立一個同名的空物件或是空陣列,然後將屬性複製到該空物件或是空陣列中。

下面是一段深層複製的程式碼(c繼承p的屬性 )

function deepcopy(p,c){
  var i;
  c=c||{};
  for (i in p){
    if(p.hasOwnProperty(i)){
      if(typeof p[i]==="object"){//注意這裡不要使用 p[i] instanceof Object 做為判斷
        c[i]=(Object.prototype.toString.call(p[i]) === "[object Array]")?[]:{};
        //上面這行是在判斷是否是陣列,如果是的話就建立一個新的空陣列,否就建立一個空物件。
        deepcopy(p[i],c[i]);//使用遞迴 複製物件內的屬性
      }else{
        c[i]=p[i];
      }
    }
  } 
  return c;
}

上面這例子可以輕鬆的把一個物件的屬性深層複製到另外一個物件中。不過,似乎漏掉了什麼?函式,沒錯上面這個方法依然沒辦法將物件中的函式深層複製到新的物件中,函式依然只是淺層複製。不過老實說我還真不知道怎麼複製函式實體出來 ==?。

那為什麼判斷屬性是否為物件時不使用 p[i] instanceof Object呢?答案是因為她會不正常的複製函式,導致函式在新的複製物件中無法被呼叫。這原因是因為函式在進行 p[i] instanceof Object的布林判斷時會是true,然後在陣列判斷是否為陣列時會是false,所以在新的複製物件中他就會等於空物件。而不是原來的函式。不過這方法確實可以正確地把函式的屬性複製過來。只是函式本身不能被呼叫就是(因為它變成普通的物件了)。

 
 

  按個讚!~支持本站!~

FB推薦載入中