理解JavaScript深淺拷貝以及方法
阿新 • • 發佈:2022-02-11
先考慮一種情況,對一個已知物件進行拷貝,編譯系統會自動呼叫一種建構函式——拷貝建構函式,如果使用者未定義拷貝建構函式,則會呼叫預設拷貝建構函式****。
執行結果:呼叫一次建構函式,呼叫兩次解構函式,兩個物件的指標成員所指記憶體相同,name指標被分配一次記憶體,但是程式結束時該記憶體卻被釋放了兩次,會造成記憶體洩漏問題!
這是由於編譯系統在我們沒有自己定義拷貝建構函式時,會在拷貝物件時呼叫預設拷貝建構函式,進行的是淺拷貝!即對指標name拷貝後會出現兩個指標指向同一個記憶體空間。
所以,在對含有指標成員的物件進行拷貝時,必須要自己定義拷貝建構函式,使拷貝後的物件指標成員有自己的記憶體空間,即進行深拷貝,這樣就避免了記憶體洩漏發生。
執行結果:呼叫一次建構函式,一次自定義拷貝建構函式,兩次解構函式。兩個物件的指標成員所指記憶體不同。
總結:淺拷貝只是對指標的拷貝,拷貝後兩個指標指向同一個記憶體空間,深拷貝不但對指標進行拷貝,而且對指標指向的內容進行拷貝,經深拷貝後的指標是指向兩個不同地址的指標。
深拷貝方法:
-
使用
JSON.parse()
與JSON.stringify()
對物件進行拷貝通常情況下,我們可以使用
JSON.parse()
與JSON.stringify()
實現物件的深克隆,如下:var clone = function (obj) { return JSON.parse(JSON.stringify(obj)); } // 這種方法只適用於純資料json物件的深度克隆,因為有些時候,這種方法也有缺陷
-
目前沒有發現bug的物件深拷貝方法
var clone = function (obj) { if (obj === null) return null if (typeof obj !== 'object') return obj if (obj.constructor === Date) return new Date(obj) if (obj.constructor === RegExp) return new RegExp(obj) var newObj = new obj.constructor() //保持繼承鏈 for (var key in obj) { if (obj.hasOwnProperty(key)) { //不遍歷其原型鏈上的屬性 var val = obj[key] newObj[key] = typeof val === 'object' ? arguments.callee(val) : val // 使用arguments.callee解除與函式名的耦合 } } return newObj }
-
展開運算子進行淺拷貝
var arr1=[1,2,5,6,4]; var arr2=[...arr1]; arr1 == arr2 // false; arr1.push(8,9,9) // (8)[1, 2, 5, 6, 4, 8, 9, 9] arr2 // (5)[1, 2, 5, 6, 4] var arr3 = arr1 arr3 // (8)[1, 2, 5, 6, 4, 8, 9, 9] arr1.push(12313,12313) // (10)[1, 2, 5, 6, 4, 8, 9, 9, 12313, 12313] arr3 // (10)[1, 2, 5, 6, 4, 8, 9, 9, 12313, 12313]