天天看點

js中深淺複制

閑言碎語

  我很早看過相關的大神的部落格,但是之前知識掌握不太好,又加上記憶力不太好,是以就忘到十裡之外了,今天刷題的時候看到一道問答題,讓說說javaScript中的深複制(深度克隆),一刹那有些懵了,就各種搜尋了解惡補一下。為了加深記憶和為自己做個筆記的驅動下,寫個部落格記錄一下。

  js中的資料類型,分為兩大類:

  基本資料類型:number、string、boolean、null、undefined (使用typeof進行檢測判斷,傳回基本資料類型,但是typeof null =>‘object’)

  引用資料類型:object(使用instanceof 進行檢測,傳回布爾值)

  兩者的差別:

  1、存儲方式不同:

  基本資料類型是将變量名和值儲存在棧記憶體中

  引用資料類型是将變量名儲存在棧記憶體中,将值儲存在堆記憶體中,棧記憶體中有指向堆中(該值)的指針。

  2、指派方式不同:

  基本資料類型是将變量名和值複制給另一個變量時,新變量将會在棧中開辟一個空間,和之前的變量/值也就無關了(忘恩。。哈哈)

  引用資料類型是将目前變量指向堆記憶體的指針指派給了新的變量,此時兩個變量共享一個值,是以改變其中一個時另外一個也會發生變化(飲水思源。。嘿嘿)

敲黑闆啦

  所謂淺複制就是隻是簡單的指派内容,當原内容變化是,新的内容随着變化,看起來很沒有主見的樣子哈(。。。),深複制就是不管原本的内容如何變化,我的内容就是不變,你變或不變,我的值就是這樣不改不變。

淺複制

來個小栗子:

var arr1 = [9,3,[6,5],97,7];
var arr2 = arr1;    //[9,3,[6,5],97,7]
arr1[0] = -1;
console.log(arr2);    //[-1,3,[6,5],97,7]
           

可以看到arr2完全随着arr1的變化而變化,來個深複制

var color1 = [1,[2,3],3];
var color2 = [];
for(var i  = 0;i < color1.length;i++){
    color2[i] = color1[i]; 
}

console.log(color2);   //[1, [2,3], 3]
color[0] = -1;
color[1][0] = 0;
console.log(color2);     //[1, [0,3], 3]
           

上面的代碼隻能淺顯的完成一層深複制,想要完全脫離color1的魔爪,還是不能實作。。。js數組中的slice()、concat()、Object.assign()、展開運算符(…)也是達到淺複制效果(請自行實作)。

深複制

  這個呢稍微難了解一點,但是基礎程度好的童鞋肯定會一笑而過的。有如下三種方式來實作。

1、通過遞歸的方式

  在網上搜尋你會發現,這中是出現率很高的一種方式,主要原理是對原對象進行遞歸檢查,像上面例子數組中的數組一樣,一旦發現子屬性中還可以進行周遊,那麼,就二話不說的再對其子屬性進行周遊,直到隻有自身為止(真是榨幹榨淨啊。。。)

代碼實作:

function DeepCopy(obj){
    var res;
    if(Object.prototype.toString.call(obj)=='[object Array]'){    //判斷傳入參數是不是數組
        res = [];   //是數組的話定義為數組類型
        for(var i = 0;i<obj.length;i++){
            res[i] = DeepCopy(obj[i]);   //對其子元素再進行遞歸周遊
        }
    }else if(Object.prototype.toString.call(obj) == '[object Object]'){    //判斷傳入參數是不是對象
        res = {};
        for(var key in obj){
            res[key] = DeepCopy(obj[key]);
        }
    }else{
        return obj;
    }
    return res;
}
           

使用這個函數再去重新複制 color2 就會有不一樣的效果,其中Object.prototype.toString這個方法是幹啥的呢??上面也說了使用typeof隻能判斷基本的類型,如果硬是用這個判斷引用類型就會傳回 “object”,是以呢可以通過Object.prototype.toString方法,判斷某個對象屬于哪種内置類型。

2、JSON.stringify與JSON.parse

var arrs = [9,3,[6,5],97,7];

function DeepCopy(obj){
    var _str = JSON.stringify(obj);   //轉換為基本類型 
    var news = JSON.parse(_str);  //再次轉換,為json格式 再複制
    return news;
}
var ac = DeepCopy(arrs);
console.log(arrs,ac);
arrs[0] = 0;
arrs[2][0] = 0;
console.log(arrs,ac);
           
js中深淺複制

3、extend

  文法:$.extend( [deep ], target, object1 [, objectN ] )

  deep:訓示是否深度合并對象,,為true為深拷貝,為false,則為淺拷貝

  target:Object類型 目标對象,其他對象的成員屬性将被附加到該對象上

  object1:可選。 Object類型 第一個被合并的對象

var a1 = [1,2,[3,4],5];
var a2 = $extend(true,[],a1);
console.log(a1,a2);
a1[0] = 0;
a1[2][0] = -1;
console.log(a1,a2);
           

官方的總結: 希望我寫的這篇文章可以幫助你們,站在巨人的肩上可以看的更遠,我寫的之前也是看了好多關于這方面的知識。。有錯或者寫的不恰當的地方歡迎指出。

  最後祝大家生活越來越美好,事業越來越順利!

繼續閱讀