由于引用类型直接复制的效果是地址的复制,只是两个变量指向了同一块内存。
var a = [1,2,3];
var b = a;
b.push[4];
console.log(b);//[1,2,3,4]
console.log(a);//[1,2,3,4]
所以有了浅拷贝和深拷贝。
浅拷贝
数组的浅拷贝
var a = [1,2,3];
var b = [];
for(var i in a){
b[i] = a[i];
}
b.push(4);
console.log(a);//[1,2,3]
console.log(b);//[1,2,3,4]
对象的浅拷贝
var obj1 = {
a: '1',
b: '2',
c: '3'
}
var obj2 = {};
for(i in obj1}{
obj2[i] = obj1[i];
}
obj2['d'] = 4;
console.log(obj1);//{a: 1,b: 2,c: 3}
console.log(obj2);//{a: 1,b: 2,c: 3, d:4}
但浅拷贝只能实现一层的拷贝,无法实现更深层次的拷贝
function shallowCopy(obj1,obj2){
for(var key in obj1){
if(obj1.hasOwnProperty(key)){
obj2[key] = obj1[key];
}
}
}
var obj1 = {
fruits: ['apple', 'peach'],
num: 100
};
var obj2 = {};
shallowCopy(obj1,obj2);
obj2.fruits[0] = 'orange';
console.log(obj1.fruits[0]); //orange
console.log(obj2.fruits[0]); //orange
hasOwnProperty方法是为了防止遍历到数组或对象的继承属性
浅拷贝还可以通过Object.assign方法来实现
Object.assign()
方法用于将所有可枚举属性的值从一个或多个源对象复制到目标对象。它将返回目标对象。
Object.assign()
var obj1 = {a:1,b:{c:2,d:3}};
var obj2 = Object.assign({},obj1);
obj2.a = 4;
obj2.b.c = 5;
console.log(obj1.a);//1
console.log(obj2.a);//4
console.log(obj1.b.c);//5
console.log(obj2.b.c);//5
Array的slice和concat方法不修改原数组,只会返回一个浅复制了原数组中的元素的一个新数组。
深拷贝
通过递归调用浅拷贝的方式来实现深拷贝
function deepCopy(obj){
var objArray = Array.isArray(obj)?[]:{};
if(obj && typeof obj === "object"){
for(var key in obj){
if(obj.hasOwnProperty(key)){
if(obj[key] && typeof obj[key] === "object"){
objArray[key] = deepCopy(obj[key]);
}else{
objArray[key] = obj[key];
}
}
}
}
return objArray;
}
var obj1 = { fruits: ['apple', 'peach'], num: 100 };
var obj2 = deepCopy(obj1);
obj2.fruits[0] = 'orange'; console.log(obj1.fruits[0]); //apple
console.log(obj2.fruits[0]); //orange
还可以通过Json.parse实现深拷贝
var obj1 = {a:1,b:{c:2,d:3}};
var obj2 = JSON.parse(JSON.stringify(obj1));
obj2.a = 4;
obj2.b.c = 5;
console.log(obj1.a);//1
console.log(obj2.a);//4
console.log(obj1.b.c);//2
console.log(obj2.b.c);//5
原理:用JSON.stringify将对象转成字符串,再用JSON.parse把字符串及解析成对象,一去一来,新的对象产生了,而且对象会开辟新的栈,实现深拷贝。
jQuery的extend可以深拷贝也可以浅拷贝
需要注意的是,如果对象比较大,层级也比较多,深复制会带来性能上的问题。在遇到需要采用深复制的场景时,可以考虑有没有其他替代的方案。在实际的应用场景中,也是浅复制更为常用。