首頁  >  文章  >  web前端  >  JavaScript物件的深淺複製實例詳解

JavaScript物件的深淺複製實例詳解

零下一度
零下一度原創
2017-04-19 15:58:001186瀏覽

從層次來看,物件的複製可以簡單地分為淺複製和深複製,顧名思義,淺複製是指只複製一層物件的屬性,不會複製物件中的物件的屬性,物件的深複製會複製物件中層層嵌套的物件的屬性。本文是我在複製物件方面的一些心得總結,由淺複製到深複製,有興趣的朋友一起學習吧

前言

從層次來看,物件的複製可以簡單地分為淺複製和深複製,顧名思義,淺複製是指只複製一層物件的屬性,不會複製物件中的物件的屬性,物件的深複製會複製對象中層層嵌套的物件的屬性。

在複製物件時,除了要複製物件的屬性外,還要兼顧到是否保留了物件的constructor屬性,是否對每一種資料類型(Javascript常見的資料類型有String, Number,Boolean,Data,RegExp,Array,Funtion,Object)都實現正確的複製。在專案中,我們可以根據實際情況,決定需要實現什麼樣程度的複製。

本文是我在複製物件方面的一些心得總結,由淺複製到深複製,由只複製簡單屬性到複製Function,RegExp等複雜屬性,層層遞進。如有陳述不當之處,煩請指出,不勝感激。

正文

淺複製

淺複製只會依序複製物件的每一個屬性,不會對這些屬性進行遞歸複製。下面是一個簡單的淺複製實作。

//对象浅复制        
function shadowCopy(obj){
 if(typeof obj !== 'object') return obj;
 for(var prop in obj){
  if(obj.hasOwnProperty(prop)){
  newObj[prop] = obj[prop];
  }
 }
 return newObj;
 }

仔細觀察,不難發現上述方法的缺陷:

1.無法正確實作陣列的淺複製

2.複製操作遺失了物件的constructor屬性

好,我們現在已經發現了問題所在,只需針對性地解決,一個還算完美的淺複製物件的方法就誕生了!


//对象浅复制
 function shadowCopy(obj){
  if(typeof obj !== 'object') return ;
  var newObj;
  //保留对象的constructor属性
  if(obj.constructor === Array){
  newObj = [];
  } else {
  newObj = {};
  newObj.constructor = obj.constructor;
  }
  for(var prop in obj){
  if(obj.hasOwnProperty(prop)){
   newObj[prop] = obj[prop];
  }
  }
  return newObj;
 }

瀏覽器中測試一下:

var arr1 = [0,1,2];
 console.log(arr1);
 console.log(shadowCopy(arr1));
 var arr2 = [0,1,2,[3,4,5]],
 arr2Copy = shadowCopy(arr2);
 console.log(arr2);
 console.log(arr2Copy);
 arr2Copy[3][0] = 6;
 console.log(arr2[3][0]); //6

JavaScript物件的深淺複製實例詳解

Good! 可以正確實作數組複製和並且保留constructor了,但細心的你一定發現了,淺複製後的對象的arr2Copy[3] 和arr2[3] 指向的是一個對象,改變其中一個,同時也會改變另一個。我們想要實現的是 複製,但這不是複製呀!
這是淺複製的一個弊端所在,接下讓我們看看深複製是怎麼解決這個問題的。

深複製

深複製需要層層遞歸,複製物件的所有屬性,包括物件屬性的屬性的屬性....(暈~)
如果只是需要簡單地複製物件的屬性,而不用考慮它的constructor,也不用考慮函數,正則,Data等特殊資料類型,那麼這裡有一個深複製的小trick,兩行程式碼即可:


function deepCopy(obj){
 if(typeof obj !== "object"){ return ;}
 var str = JSON.stringify(obj);
 return JSON.parse(str);
}

大多數情況下,上面的就可以滿足要求了,但一些時候,我們需要把函數,正則等特殊資料類型也考慮在內,或者當前環境不支持JSON時,上面的方法也就不適用了。這時,我們可以透過遞歸來實現物件的深層複製,如下:


function deepCopy(obj){
 if(typeof obj !== "object"){ return ;}
 var newObj;
 //保留对象的constructor属性
 if(obj.constructor === Array){
 newObj = [];
 } else {
 newObj = {};
 newObj.constructor = obj.constructor;
 }
 for(var prop in obj){
 if(typeof obj[prop] === 'object'){
  if(obj[prop].constructor === RegExp ||obj[prop].constructor === Date){
  newObj[prop] = obj[prop];
  } else {
  //递归
  newObj[prop] = deepCopy(obj[prop]);
  }
 } else {
  newObj[prop] = obj[prop];
 }
 }
 return newObj;
}

先用上面的範例測試:

JavaScript物件的深淺複製實例詳解

棒!可以正確實現多維數組的複製,再看是否能實現函數和正規的複製:


#
function Person(name){
 this.name = name;
 this.age = age;
 this.search = new RegExp(name);
 this.say = function(){
 console.log(this.name + "今年" + this.age + "岁了");
 }
}
var p1 = new Person("Claiyre",20),
 p2 = deepCopy(p1);
console.log(p1);
console.log(p2);
p2.age = 22;
p1.say();
p2.say();

JavaScript物件的深淺複製實例詳解

圓滿完成! !

稍加整理,我們就可以得到一個較為通用的js物件複製函數:


#
function deepCopy(obj){
 var newObj = obj.constructor === Array ? []:{};
 newObj.constructor = obj.constructor;
 if(typeof obj !== "object"){ 
 return ;
 } else if(window.JSON){
 //若需要考虑特殊的数据类型,如正则,函数等,需把这个else if去掉即可
 newObj = JSON.parse(JSON.stringify(obj));
 } else {
 for(var prop in obj){
  if(obj[prop].constructor === RegExp ||obj[prop].constructor === Date){
  newObj[prop] = obj[prop];
  } else if(typeof obj[prop] === 'object'){
  //递归
  newObj[prop] = deepCopy(obj[prop]);
  } else {
  newObj[prop] = obj[prop];
  }
 }
 } 
 return newObj;
}

##結語

物件導向的程式語言,其核心是對象,因此深入了解對象的相關操作,縱向比較異同,對學習過程是極有好處的。

以上是JavaScript物件的深淺複製實例詳解的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn