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


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]

但是當我們改變一個數組元素時,我們看一下會發生什么

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

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

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: "男"}

在開發中一般不想有這種情況發生我們就用到了復制這個功能下面我們來介紹一下都有哪些復制,深度復制和淺復制有什么區別

一、數組的深淺復制
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())方法解決一下;

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())好像萬事大吉了,復制解決了,我們再讓數據復雜一下看看

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())不能復制帶有函數的數組,這要怎么辦呢

我們先來看一下對象的復制,后面一起說


二、對象的深淺復制
我們先來看一下數組淺復制的一些方法 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
不想下載的可以直接在下方留言即可,樓主會乖乖奉上@~@。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM