摘要:本文是我在復制對象方面的一些心得總結,由淺復制到深復制,由只復制簡單屬性到復制,等復雜屬性,層層遞進。如有陳述不當之處,煩請指出,不勝感激。下面是一個簡單的淺復制實現。
前言
從層次上來看,對象的復制可以簡單地分為淺復制和深復制,顧名思義,淺復制是指只復制一層對象的屬性,不會復制對象中的對象的屬性,對象的深復制會復制對象中層層嵌套的對象的屬性。
在復制對象時,除了要復制對象的屬性外,還要兼顧到是否保留了對象的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
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; }
先用上面的例子測試:
棒!可以正確實現多維數組的復制,再看是否能實現函數和正則的復制:
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();
圓滿完成!!
稍加整理,我們就可以得到一個較為通用的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; }結語
面向對象的編程語言,其核心是對象,因此深入了解對象的相關操作,縱向比較異同,對學習過程是極有好處的。
博客原文地址:Claiyre的個人博客 https://claiyre.github.io/
博客園地址:http://www.cnblogs.com/nuannuan7362/
如需轉載,請在文章開頭注明原文地址
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/82294.html
摘要:開門見山,有人叫對象的復制為深復制淺復制,也有人叫深拷貝淺拷貝。高級屬性修改深拷貝滿足對象的復制,淺拷貝影響原數組。關于對象的深淺拷貝,暫且探索到這里,后續有新發現再進行補充。 showImg(https://segmentfault.com/img/remote/1460000014305581); 開門見山,有人叫對象的復制為深復制淺復制,也有人叫深拷貝淺拷貝。其實都是copy。 ...
摘要:基本數據類型的復制很簡單,就是賦值操作,所以深淺拷貝也是針對,這類引用類型數據。它會拋棄對象的。另外,查資料過程中還看到這么一個詞結構化克隆算法還有這一篇資料也有參考,也寫得比較詳細了的深淺拷貝 基本數據類型的復制很簡單,就是賦值操作,所以深淺拷貝也是針對Object,Array這類引用類型數據。 淺拷貝對于字符串來說,是值的復制,而對于對象來說則是對對象地址的復制;而深拷貝的話,它不...
摘要:基本類型指的是簡單的數據段,而引用類型指的是一個對象保存在堆內存中的地址,不允許我們直接操作內存中的地址,也就是說不能操作對象的內存空間,所以,我們對對象的操作都只是在操作它的引用而已。 工作中經常會遇到需要復制 JavaScript 數據的時候,遇到 bug 時實在令人頭疼;面試中也經常會被問到如何實現一個數據的深淺拷貝,但是你對其中的原理清晰嗎?一起來看一下吧! 一、為什么會有深淺...
閱讀 2101·2023-04-25 20:52
閱讀 2487·2021-09-22 15:22
閱讀 2125·2021-08-09 13:44
閱讀 1770·2019-08-30 13:55
閱讀 2809·2019-08-23 15:42
閱讀 2284·2019-08-23 14:14
閱讀 2877·2019-08-23 13:58
閱讀 3008·2019-08-23 11:49