1. 程式人生 > >js物件的深拷貝及其的幾種方法

js物件的深拷貝及其的幾種方法

深拷貝和淺拷貝是javascript中一個比較複雜的問題,也是面試官最喜歡問的問題之一,通過這個為可以看出是否入門,深拷貝和淺拷貝也是初學者經常犯錯一個點。

簡單來說深拷貝是拷貝儲存在棧中的物件,而淺拷貝是從記憶體中拷貝,這就涉及到資料存放位置了,總所周知,資料大體可以分為兩種資料型別,一種是基本資料型別,資料結構不是很複雜,單獨可以存在記憶體中就可以,而另一種是複雜資料型別,也叫引用資料型別,例如陣列和物件,是放在棧中儲存的,而基本資料型別是放在記憶體中的,不涉及深拷貝和淺拷貝,也可以說基本資料型別都是深拷貝

而引用型別資料儲存比較複雜,例如var a=[1,3,4]  這句話的儲存就是首先在記憶體開闢一個空間,但是記憶體當中不可以儲存這種複雜資料型別,所以要把這種結構放到棧當中,棧相當於一個密碼箱,而鑰匙存在記憶體當中,這就構成了一個儲存關係,淺拷貝var b=a簡單來說就是把這份鑰匙複製了一份,但記憶體當中的資料並沒有複製,所以如果改變a相應b也會改變

而深拷貝則需要在棧中在生成一個密碼箱,生成一把新鑰匙(鑰匙2),這樣深拷貝的兩種數值不會相互影響,也可以說沒有任何關係了

方法:

1:jq使用,$.extend({},obj)

2:Object.assign({},obj)

這兩種比較基礎,估計都會使用

3:clone(obj)

var clone = function (obj) { return JSON.parse(JSON.stringify(obj)); }

這種方法有種缺陷,這種方法會忽略值為function以及undefied的欄位,而且對date型別的支援也不太友好。 

4:clone(obj)

var clone = function (obj) { 
    if(obj === null) return null 
    if(typeof obj !== 'object') return obj;
    if(obj.constructor===Date) return new Date(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;  
}; 

這種方法也就使封裝最好的深拷貝的方法,以下為解釋:

1、用new obj.constructor ()建構函式新建一個空的物件,而不是使用{}或者[],這樣可以保持原形鏈的繼承;
2、用obj.hasOwnProperty(key)來判斷屬性是否來自原型鏈上,因為for..in..也會遍歷其原型鏈上的可列舉屬性。
3、上面的函式用到遞迴演算法,在函式有名字,而且名字以後也不會變的情況下,這樣定義沒有問題。但問題是這個函式的執行與函式名 factorial 緊緊耦合在了一起。為了消除這種緊密耦合的現象,需要使用 arguments.callee