javascript 數組和對象的淺複製和深度複製 assign/slice/concat/JSON.parse(JSON.stringify())

javascript 數組和對象的淺度複製和深度複製
在日常咱們用 ‘=’來用一個變量引用一個數組或對象,這裏是‘引用’而不是複製下面咱們看一個例子引用和複製是什麼概念javascript

var arr=[1,2,3,'f',2,'s',1];
var cloneArr=arr; //這時cloneArr確實是[1,2,3,'f',2,'s',1]
//咱們來打印看一下
console.log(cloneArr); //咱們來打印一下看看 [1,2,3,'f',2,'s',1]
console.log(arr); //這個也同樣 [1,2,3,'f',2,'s',1]

//打印結果
[1,2,3,"f",2,"s",1]
[1,2,3,"f",2,"s",1]

可是當咱們改變一個數組元素時,咱們看一下會發生什麼java

arr[0]='小明';
console.log('arr:'+arr); //這個打印是 ["小明", 2, 3, "f", 2, "s", 1] 沒有任何問題
console.log('cloneArr:'+cloneArr); //咱們打印一下cloneArr 發現也變了 ["小明", 2, 3, "f", 2, "s", 1]

//咱們在試試改變cloneArr,看看會發生什麼

cloneArr.push('我是cloneArr');
console.log('arr:'+arr); //["小明", 2, 3, "f", 2, "s", 1, "我是cloneArr"]
console.log('cloneArr:'+cloneArr); //這個也變了 ["小明", 2, 3, "f", 2, "s", 1, "我是cloneArr"]

//打印結果
arr:小明,2,3,f,2,s,1
cloneArr:小明,2,3,f,2,s,1
arr:小明,2,3,f,2,s,1,我是cloneArr
cloneArr:小明,2,3,f,2,s,1,我是cloneArr

對象也是一個道理咱們來看一個例子git

var obj={
        name:'小明',
age:18,
tel:'13108123123',
sex:'男'
    };
cloneObj=obj;
cloneObj['name']='小紅';
console.log(obj); // {name: "小紅", age: 18, tel: "13108123123", sex: "男"}
//打印結果:
Object {name:"小紅", age: 18, tel:"13108123123", sex: "男"}

在開發中通常不想有這種狀況發生咱們就用到了複製這個功能下面咱們來介紹一下都有哪些複製,深度複製和淺複製有什麼區別github

1、數組的深淺複製
1.咱們先來看一下數組淺複製的一些方法 slice concat   淺複製沒有函數時for循環遍歷就不說了這樣畫蛇添足,
通常狀況下數組淺複製能夠用slice和concat解決,咱們看一下例子數組

var arr=[1,2,3,'f',2,'s',1];
var cloneArr1=arr.slice();
var cloneArr2=arr.concat();
console.log('未更改前:'+'\n'+arr+'\n'+cloneArr1+'\n'+cloneArr2); //是同樣的

//爲了方便看出來這裏每一個更改不一樣元素
arr[0]='我是arr的第一項';
cloneArr1[1]='我是cloneArr1的第二項';
cloneArr2.push('我是cloneArr新添加');

//咱們在打印一下看看
console.log('更改後:'+'\n'+arr+'\n'+cloneArr1+'\n'+cloneArr2);

//打印結果
更改前:
1,2,3,f,2,s,1
1,2,3,f,2,s,1
1,2,3,f,2,s,1
更改後:
我是arr的第一項,2,3,f,2,s,1
1,我是cloneArr1的第二項,3,f,2,s,1
1,2,3,f,2,s,1,我是cloneArr新添加

從上面例子能夠看出當咱們把數組截取或拼接後返回的新數組就和原數組就不是引用關係了,而是一個新的獨立的數組,具體能夠看Array中 slice 和 concat 的介紹 https://blog.csdn.net/xiaoxiaoshuai__/article/details/77840759函數

上面看似輕鬆完成了淺複製,
那咱們建一個二維數組看一下淺複製還能完成任務嗎
咱們在看看這個例子測試

var arr2=[1,2,3,4,5,6,7,['q','w','e','w'],8,{name:'小明',age:18},9,7,54];
var cloneArr1=arr2.slice();
var cloneArr2=arr2.concat();
console.log(arr2); //是同樣的
console.log(cloneArr1); //是同樣的
console.log(cloneArr2); //是同樣的

//咱們在這裏給該元素試一下
arr2[0]=101;
console.log(arr2); //更改了 [101,2,3,4,5,6,7,['q','w','e','w'],8,{name:'小明',age:18},9,7,54];
console.log(cloneArr1); //沒變 [1,2,3,4,5,6,7,['q','w','e','w'],8,{name:'小明',age:18},9,7,54];
console.log(cloneArr2); //沒變 [1,2,3,4,5,6,7,['q','w','e','w'],8,{name:'小明',age:18},9,7,54];

//看似沒有什麼問題,咱們在試一下更改一下二級數組裏面的元素
arr2[7][2]='eee000';
console.log(arr2); //更改了 [101,2,3,4,5,6,7,['q','w','eee000','w'],8,{name:'小明',age:18},9,7,54];
console.log(cloneArr1); //這個怎麼也更改了? [1,2,3,4,5,6,7,['q','w','eee000','w'],8,{name:'小明',age:18},9,7,54];
console.log(cloneArr2); //這個怎麼也更改了? [1,2,3,4,5,6,7,['q','w','eee000','w'],8,{name:'小明',age:18},9,7,54];


這時發現二級數組用這些方法好像也不行,
那咱們來試一下JSON.parse(JSON.stringify())方法解決一下;this

var arr3=[1,2,3,4,5,6,7,['q','w','e','w'],8,{name:'小明',age:18},9,7,54];
var cloneArr1=JSON.parse(JSON.stringify(arr3));

console.log(arr3); //[1,2,3,4,5,6,7,['q','w','e','w'],8,{name:'小明',age:18},9,7,54];
console.log(cloneArr1); //成功複製過來了 [1,2,3,4,5,6,7,['q','w','e','w'],8,{name:'小明',age:18},9,7,54];

//那咱們改變一下值看一下
arr3[0]=101;
arr3[7][1]='qqqpppqqpp';
arr3[9]['name']='飛上天';

console.log(arr3); //[101,2,3,4,5,6,7,['q','qqqpppqqpp','e','w'],8,{name:'飛上天',age:18},9,7,54];
console.log(cloneArr1); //這樣好像能夠 [1,2,3,4,5,6,7,['q','w','e','w'],8,{name:'小明',age:18},9,7,54];


用JSON.parse(JSON.stringify())好像萬事大吉了,複製解決了,咱們再讓數據複雜一下看看spa

function fn1(age){
    alert(age);
}
var b="bbb";
var arr3=[6,7,['q','w','e','w'],8,{name:'小明',age:18,fn:function(name){alert(name);}},9,7,54,fn1,b];
var cloneArr1=JSON.parse(JSON.stringify(arr3))
console.log(arr3); //[,6,7,['q','w','e','w'],8,{name:'小明',age:18,fn:function(name){alert(name);}},9,7,54,function function,'bbb'];
console.log(cloneArr1); //[6,7,['q','w','e','w'],8,{name:'小明',age:18},9,7,54,null,'bbb'];這是發現fn函數和函數名沒有被複制上


咱們發現JSON.parse(JSON.stringify())不能複製帶有函數的數組,這要怎麼辦呢.net

咱們先來看一下對象的複製,後面一塊兒說


2、對象的深淺複製
咱們先來看一下數組淺複製的一些方法 assign

function fn2(age){
    alert(age);
}
var obj={
    name:'小明',
    age:18,
    tel:'13108123123',
    sex:'男',
    fn:function(name){
        console.log(name)
    },
    fn2:fn2
};
cloneObj=Object.assign({},obj);
console.log(obj);
console.log(cloneObj); //這裏成功複製了

//咱們改變一下試試

obj['name']='小紅';
console.log(obj); //改變了
console.log(cloneObj); //沒改變


這樣複製成功了,正常的對象是能夠了,咱們要是再是一下複雜一點的試試

function fn2(age){
    alert(age);
}
var obj={
    name:'小明',
    age:18,
    tel:'13108123123',
    sex:'男',
    fn:function(name){
        console.log(name)
    },
    fn2:fn2,
    obj2:{
        name:'小紅',
        age:16
    },
    li:[12,23,45,23]
};
cloneObj=Object.assign({},obj);
console.log(obj);
console.log(cloneObj); //這裏成功複製了

//咱們改變一下試試

obj['name']='小紅紅';
obj['obj2']['name']='小明明';
obj['li'][1]=900;
console.log(obj); //改變了
console.log(cloneObj); // obj中的name沒有改變,可是obj2中的name和obj中li中的值都變了


複雜了以後好像Object.assign不能完成任務了,
那咱們在用JSON.parse(JSON.stringify()),試一下看看能問題嗎

cloneObj=JSON.parse(JSON.stringify(obj));
console.log(obj);
console.log(cloneObj); //這裏成功複製了

//咱們改變一下試試

obj['name']='小紅紅';
obj['obj2']['name']='小明明';
obj['li'][1]=900;
console.log(obj); 
console.log(cloneObj); // 從打印結果來看,除了函數以外其餘的均可以深度拷貝


好像能夠的,可是咱們還記得嗎JSON.parse(JSON.stringify())不能copy 函數及函數變量

綜上所述:

數組淺複製:slice 、concat

數組深複製:JSON.parse(JSON.stringify(arr)); 不能夠解決數組中帶有函數和函數變量
對象淺複製:Object.assign({},obj) 
對象深複製:JSON.parse(JSON.stringify(arr)); 不能夠解決對象中帶有函數和函數變量


那咱們來研究一下又是多層對象或數組又有函數怎麼解決呢

好吧,百度沒有查到,本身封裝了一個方法來實現吧

function fn2(age){
    alert(age);
}
var obj={
    name:'小明',
    age:18,
    tel:'13108123123',
    sex:'男',
    fn:function(name,a,b){
this.name=name;
this.fnn=function(a,b){
            console.log(a+b)
}
    },
    fn2:fn2,
    obj2:{
name:null,
sex:'男',
age:15
    },
    li:[1,null,0,23],
    lii:[1,2,3,4,45,[1,2,3,43,3,{name:'111',age:'1',e:[2,3,4,1,1,2],fnnc:function(){console.log(11);}}],3,2,]
};

//咱們來看一下複製的用時 平均 0.4~0.9 ms以前
console.time();
var cloneObj2=clone(obj); //clone爲自定義函數這裏買個關子@~@
console.timeEnd();


obj['name']='小紅紅紅話';
obj['obj2']['name']='大紅花那個大紅花';
obj['lii'][5][1]='5656565';
obj['lii'][5][5]['name']='大紅袍';

console.log(obj); //都改變了
console.log(cloneObj2); //都沒變,ok能夠

//咱們在看看複製的函數的狀況

cloneObj2['fn2'](16); //正常彈出16


根據模擬數據測試能夠經過以上的問題深度複製應該不成問題,源碼在下面,代碼行數有點多,截圖字偏小有興趣的能夠在Git上下載看源碼:https://github.com/liushuai541013304/oject-deep-clone
不想下載的能夠直接在下方留言便可,樓主會乖乖奉上@~@。

相關文章
相關標籤/搜索