標籤:else def name clone 包含 就是 分享 改變 new
JS資料類型可以分為(ES5,暫時不考慮ES6):
單一資料型別:Number、String、undefined、boolean
複雜資料類型:Object、Array
簡單的資料類型,往往是賦值操作,而複雜資料類型是引用操作。
賦值操作我們就不講了,主要看看引用操作把
var arr = [1,2,3]; var arr2 = arr; arr2.push(4); console.log(arr);//輸出[1,2,3,4]
明明是對arr2進行的操作,為什麼arr也變化了呢?因為js儲存物件都是存地址的,所以arr2實際儲存的是:"arr在記憶體中的地址";
由此我們可以明白,既然都是指向同一個記憶體位址,當我們改變任何一個的時候,都會改變。
知道這個基本的特性那麼我們可以試圖來理解下淺複製和深複製
首先看一段代碼,我們再來講解下概念
var obj ={a:1,b:2,c:[1,2]}; var shallowCopy = shallow(obj); function shallow(obj){ var shallowObj = {}; for(var name in obj){ if(obj.hasOwnProperty(name)){ shallowObj[name] = obj[name] } } return shallowObj } console.log(shallowCopy);//輸出的就是這個對象,我們實現了簡單的淺複製;
淺複製:只會將對象的各個屬性進行依次複製,並不會進行遞迴複製,而js儲存物件都是存地址的,所以淺複製會導致obj.c和shallowCopy.c 指向同一塊記憶體位址;會導致引用。
深複製:它不僅將原對象的各個屬性逐個複製出去,而且將原對象各個屬性所包含的對象也依次採用深複製的方法遞迴複製到新對象上。這就不會存在上面obj和shallowCopy的c屬性指向同一個對象的問題。(待會貼出深複製的代碼,這是個複雜的問題)
總結:需要注意的是,如果對象比較大,層級也比較多,深複製會帶來效能上的問題。在遇到需要採用深複製的情境時,可以考慮有沒有其他替代方案,在實際的引用情境中,也是淺複製更為常用。
我現在給出一個簡單版本的深複製,可以複製對象和數組(不考慮循環參考問題,函數對象問題),如果想深入研究的話可以看下這篇文章:http://jerryzou.com/posts/dive-into-deep-clone-in-javascript/
在這裡我們只理解思想和簡單的實現,實際項目中可以考慮使用lodash(http://lodashjs.com/docs/),或者jQuery的extend的方法也同樣可以
function deepClone(obj){ var newObj = obj.constructor === Array ? []:{}; if(typeof obj !== ‘object‘){ return }else{ for(var i in obj){ if(obj.hasOwnProperty(i)){ newObj[i] = typeof obj[i] === ‘object‘?deepClone(obj[i]):obj[i]; } } } return newObj }
最核心的思想還是採用遞迴的方式,不斷進行,直到基礎資料型別 (Elementary Data Type)後,再複製
方法還有很多種,譬如還有使用JSON.stringify進行序列化,JSON.parse進行還原序列化,實現"偷懶版"的深複製...等等
js對象的深淺拷貝