1. 程式人生 > 其它 >理解JavaScript深淺拷貝以及方法

理解JavaScript深淺拷貝以及方法

先考慮一種情況,對一個已知物件進行拷貝,編譯系統會自動呼叫一種建構函式——拷貝建構函式,如果使用者未定義拷貝建構函式,則會呼叫預設拷貝建構函式****。

執行結果:呼叫一次建構函式,呼叫兩次解構函式,兩個物件的指標成員所指記憶體相同,name指標被分配一次記憶體,但是程式結束時該記憶體卻被釋放了兩次,會造成記憶體洩漏問題!

這是由於編譯系統在我們沒有自己定義拷貝建構函式時,會在拷貝物件時呼叫預設拷貝建構函式,進行的是淺拷貝!即對指標name拷貝後會出現兩個指標指向同一個記憶體空間。

所以,在對含有指標成員的物件進行拷貝時,必須要自己定義拷貝建構函式,使拷貝後的物件指標成員有自己的記憶體空間,即進行深拷貝,這樣就避免了記憶體洩漏發生。

執行結果:呼叫一次建構函式,一次自定義拷貝建構函式,兩次解構函式。兩個物件的指標成員所指記憶體不同。

總結:淺拷貝只是對指標的拷貝,拷貝後兩個指標指向同一個記憶體空間,深拷貝不但對指標進行拷貝,而且對指標指向的內容進行拷貝,經深拷貝後的指標是指向兩個不同地址的指標。

深拷貝方法:

  1. 使用JSON.parse()JSON.stringify()對物件進行拷貝

    通常情況下,我們可以使用JSON.parse()JSON.stringify()實現物件的深克隆,如下:

    var clone = function (obj) {
    	return JSON.parse(JSON.stringify(obj));
    }
    // 這種方法只適用於純資料json物件的深度克隆,因為有些時候,這種方法也有缺陷
    
  2. 目前沒有發現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
    }
    
    
  3. 展開運算子進行淺拷貝

    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]