javascript的深淺拷貝

查閱資料,看到有關深淺拷貝上面的誤區,有人說數組的slice()與concat()方法實現的是深拷貝。對此我作了一些嘗試並詳細理了一下關於js的深淺拷貝問題。首先咱們要知道數據類型的存儲方式——javascript

基本類型和引用類型

js中變量分爲兩類:java

基本類型:undefined,null,字符串,數值,布爾json

引用類型:統稱爲object。具體的有Object,Array,Function等數組

重點是這兩種類型的存儲方式了:基本類型的數據是存放在棧內存中的,而引用類型的數據是存放在堆內存中的。spa

基本數據類型,是這個樣子的:3d

 

引用類型保存在堆中,棧內的是變量的標識符以及對象在堆內存中的存儲地址,當須要訪問引用類型(如對象,數組等)的值時,首先從棧中得到該對象的地址指針,而後再從對應的堆內存中取得所需的數據。指針

因此對於這兩種類型的賦值是有不一樣的:對象

當你在複製基本類型的時候,至關於把值也一併複製給了新的變量。修改值的時候也不會影響另外一個變量的值。blog

而在複製引用類型的時候,實際上只是複製了指向堆內存的地址,即原來的變量與複製的新變量指向了同一個東西。繼承

例1.改變a,會影響b

var a = {name:"peri",age:20};
var b = a;
console.log(a === b);
a.age = 30;
console.log(a);
console.log(b);

深淺拷貝

對於僅僅是複製了引用(地址),即原來的變量和新的變量指向同一個地址,彼此之間的操做會互相影響,爲淺拷貝

而若是是在堆中從新分配內存,擁有不一樣的地址,複製後的對象與原來的對象徹底隔離,互不影響,爲深拷貝

深淺拷貝的主要區別就是:複製的是引用(地址)仍是複製的是實例。

深拷貝的實現

1.遞歸 

對於例1,咱們能夠經過遞歸的方式來實現深拷貝,對引用類型進行遍歷,一直到是基本類型爲止。

function deepClone(source){    
    if(!source && typeof source !== 'object'){      
        throw new Error('error arguments', 'shallowClone');    
    }    
    var targetObj = Array.isArray(source) ? [] : {};    
    for(var keys in source){     
        //只遍歷對象自身的屬性,而不包含繼承於原型鏈上的屬性。  
        if(source.hasOwnProperty(keys)){          
            if(source[keys] && typeof source[keys] === 'object'){  
                targetObj[keys] = deepClone(source[keys]);    //遞歸      
            }else{            
                targetObj[keys] = source[keys];         
            }       
        }    
    }    
    return targetObj; 
}
var a = {name:"peri",age:20};
var b = deepClone(a);
console.log(a === b);
a.age = 18;
console.log(a);
console.log(b);

2.JSON 對象的 parse 和 stringify

stringify把一個 js 對象序列化爲一個 JSON 字符串。parse把 JSON 字符串反序列化爲一個 js 對象,這兩個方法實現的是深拷貝。

var obj = {name:'pp',age:24,company : { name : 'AAA', address : '深圳'} };
var obj_json = JSON.parse(JSON.stringify(obj));
console.log(obj === obj_json);
obj.company.name = "BBB";
obj.name = "peri";
console.log(obj);
console.log(obj_json);

3.jQuery中的 extend方法

jQuery的$.extend方法是咱們在開發中常常用到的方法,用於合併若干個對象。

可用於深淺拷貝,第一個參數爲true深拷貝。爲false或者沒有爲淺拷貝。

例2.深拷貝

var obj = {name:'pp',age:24,company : { name : 'AAA', address : '深圳'} };
var obj_json = $.extend(true, {}, obj);
console.log(obj === obj_json);
obj.company.name = "BBB";
obj.name = "peri";
console.log(obj);
console.log(obj_json);

例2.2淺拷貝

slice()與concat()方法

最後再來討論一下最初關於數組的slice()與concat()方法是否深拷貝。

例3.slice()方法

var a = [1,2,3];
var b = a.slice();
console.log(b === a);
a[0] = 4;
console.log(a);
console.log(b);

能夠看到,改變a並無影響b!那麼就說明slice()是深拷貝了嗎?沒有那麼簡單!

例3.1

var a = [[1,2,3],4,5];
var b = a.slice();
console.log(a === b);
a[0][0] = 6;
console.log(a);
console.log(b);

這很明顯說明slice()不是深拷貝!

原來Array 的 slice() 和 concat ()方法,對於第一層的值都是深拷貝而到第二層的時候 Array的slice() 和 concat()方法就是複製引用 。(concat與slice結果相同,這裏再也不舉例)。

相關文章
相關標籤/搜索