JavaScript中的淺拷貝與深拷貝
學了這麼長時間的JavaScript想必大家對淺拷貝和深拷貝還不太熟悉吧,今天在項目中既然用到了,早晚也要理清一下思路了,在了解之前,我們還是先從JavaScript的資料型別存放的位置堆疊開始說起吧!
#現在我們帶著問題來完成問題。學習!
我們都知道:在電腦領域中,堆疊是兩種資料結構,它們只能在一端(稱為堆疊頂(top))對資料項目進行插入和刪除。
堆疊:佇列優先,先進先出;由操作系統自動指派釋放 ,存放函數的參數值,局部變數的值等。其操作方式類似於資料結構中的堆疊。
堆:先進後出;動態分配的空間 一般由程式設計師指派釋放, 若程式設計師不釋放,程式結束時可能由OS回收,分配方式倒是類似鍊錶。
以上都屬於電腦基礎部分,在此都不詳細贅述了,下面我們聯絡JavaScript來剖析一下堆疊。
JavaScript的資料型別分為兩大種:
1. 基本型別:Undefined、Null、Boolean、Number 和String,這5中基本資料型別可以直接存取,他們是按照值進行分配的,存放在堆疊(stack)記憶體中的簡單資料段,資料大小確定,記憶體空間大小可以分配。
2. 引用型別:即存放在堆(heap)記憶體中的對象,變數實際保存的是指針,這個指標指向另一個位置。
以上我們知道了什麼是堆疊,和JavaScript的資料類型,下面我們根據js的資料類型來說明一下他們的拷貝情況:
var obj1 = {name:'bangbang',age:18}; var b = obj1; var c = obj1.age; console.log(b.name); //bangbang console.log(c); //18//改变b和c的值 b.name = 'yanniu'; c = 22; console.log(obj1.name); //yanniu console.log(obj1.age); //18
以上看出:當我們改變b的資料的時候,我們看到了obj1.name的資料也在改變,但是我們改變c的資料的時候發現,obj1.age的值沒有變化,這說明了:b和obj1變數操作的是同一個對象,c和obj1完全獨立的。圖示如下:
根據上面的陳述,基本型別拷貝的時候只是在記憶體中又開闢了新的空間,和它的父元素(再次我們稱被拷貝的物件為父元素)屬於互不想幹的東西,因此深淺拷貝是相對於引用類型的,以便於我們對引用類型父物件的保存! 嘿嘿!我們接著看!
例如:
var father1 = {name:'shangdi',age:1000,job:['teacher','cook']};//浅拷贝函数 function copy(obj){ var childs = {}; for(var key in obj){ childs[key] = obj[key]; } return childs; }var child1 = copy(father1); console.log(child1); //{ name: 'shangdi', age: 1000 } console.log(typeof child1); //object //改变子对象的name属性,发现对父对象的name没有影响 哈哈! child1.name = 'bangbang'; console.log(father1); //{ name: 'shangdi', age: 1000 } console.log(child1); //{ name: 'bangbang', age: 1000 } //注意:这次改变子对象的job属性也就是改变数组,//发现对父对象的job竟然有影响,吓死宝宝了,那怎么办呢,那这个copy有什么用呢是吧! child1.job.push('programer'); console.log(father1); //{ name: 'shangdi',age: 1000,job: [ 'teacher', 'cook', 'programer' ] } console.log(child1); //{ name: 'shangdi',age: 1000,job: [ 'teacher', 'cook', 'programer' ] }
由上面可分析:淺拷貝的時候,當我們改變子物件的陣列的時候,父物件竟然也跟著改變,也就是說:子物件和父物件在淺拷貝的時候他們指向同一個記憶體的陣列:由圖所示:
#
如果我們想要讓子物件的拷貝和父物件沒有一點關聯,那麼我們就必須使用到深度拷貝!嘿嘿!兒子也不能完全跟著爹長啊!
深度拷貝就是把父物件拷貝到子物件上,而且兩者的記憶體和以後的運算都互不影響的拷貝!
function deepCopy(obj){ var o; switch(typeof obj){ case 'undefined': break; case 'string' : o = obj + '';break; case 'number' : o = obj - 0;break; case 'boolean' : o = obj;break; case 'object' : if(obj === null){ o = null; }else{ if(obj instanceof Array){ o = []; for(var i = 0, len = obj.length; i < len; i++){ o.push(deepCopy(obj[i])); } }else{ o = {}; for(var k in obj){ o[k] = deepCopy(obj[k]); } } } break; default: o = obj;break; } return o; }
#
以下是一些克隆的方法供大家參考,不過他們有區別,自己試驗:
方法二:最簡單的
function deepCopy(obj) { return JSON.parse(JSON.stringify(obj)); }
方法三:
function deepCopy(obj){ var newobj, obj; if (obj.constructor == Object){ newobj = new obj.constructor(); }else{ newobj = new obj.constructor(obj.valueOf());//valueOf()方法返回 Array 对象的原始值 } for(var key in obj){ if ( newobj[key] != obj[key] ){ if ( typeof(obj[key]) == 'object' ){ newobj[key] = deepCopy(obj[key]); }else{ newobj[key] = obj[key]; } } } newobj.toString = obj.toString; newobj.valueOf = obj.valueOf; return newobj; }
方法四:
var cloneObj = function(obj){ var str, newobj = obj.constructor === Array ? [] : {}; if(typeof obj !== 'object'){ return; } else if(window.JSON){ str = JSON.stringify(obj), //系列化对象 newobj = JSON.parse(str); //还原 } else { for(var i in obj){ newobj[i] = typeof obj[i] === 'object' ? cloneObj(obj[i]) : obj[i]; } } return newobj; };
方法五:(JavaScript物件導向程式設計指南)
function deepCopy(p,c){ c = c || {}; for (var i in p){ if(p.hasOwnProperty(i)){ if(typeof p[i] === 'object'){ c[i] = Array.isArray(p[i]) ? [] : {}; deepCopy(p[i],c[i]); }else{ c[i] = p[i]; } } } return c; }
以上是什麼是Js中的淺、深拷貝的詳細內容。更多資訊請關注PHP中文網其他相關文章!