Js对象的浅复制与深复制
js对象的复制分为浅复制和深度复制两种:
浅复制得到的子对象的属性中,如果有对象或数组形式的值,则与原对象属性中的值引用的是同一个内存地址,只要有一个对象的该属性被修改,两个对象都会被影响。
而深复制就是将属性对象复制到不同的内存地址里,修改新对象,原对象不会被影响。
浅复制
先从js的数据类型入手,为什么会出现浅复制?
js的数据类型分为两种:简单类型(也叫基本数据类型)和复杂数据类型(也叫引用数据类型)。
- 简单数据类型:number,string,boolean,null,undefined;
- 复杂数据类型:object,array,function,date;
简单类型通常是赋值操作,而复杂类型通常是引用操作。
看下面一个例子:
var a = 20;
var b = a; //赋值操作
b++; // 21
console.log(a); //20
var obj1 = {a:1,b:2};
var obj2 = obj1; // 引用同一个地址,此时 obj2 = {a:1,b:2}
obj2.a = "a"; //修改obj2的属性,obj1也跟着变,因为是同一个内存地址
console.log(obj1); // {a:"a",b:2}
console.log(obj2); // {a:"a",b:2}
再来看一个浅复制例子
var obj = {a:1,b:2,c:[1,2]};
var subObj = copyObj(obj);
function copyObj(o){
var tmpObj = {};
for(var name in o){
if(o.hasOwnProperty(name)){ //依次复制
tmpObj[name] = o[name];
console.log(name,o[name]);
}
}
return tmpObj
}
console.log(subObj); // {a:1,b:2,c:[1,2]}
subObj.c[0]="hello";
console.log(subObj); //{a:1,b:2,c:["hello",2]}
console.log(obj); //{a:1,b:2,c["hello",2]}
//因为是浅复制,obj.c和subObj.c指向的是内存里的同一个位置,修改其中一个就会影响另外一个,就会出现引用错误
因为浅复制是把对象属性的每一个值依次复制,并没有进行递归操作,所以,在遇到属性值是对象的时候,也仅仅是把引用地址传递给新对象的属性,而并未真正开辟新的内存地址。上面的例子中,obj.c 和 subObj.c 引用同一个内存地址,所以修改任意一个,都是改变同一个内存地址。
深复制的例子
var obj = {a:1,b:2,c:[1,2]};
function deepClone(obj){
var newObj = obj.constructor === Array?[]:{};
if(typeof obj !== "object"){
return
}else{
for(var i in obj){
if(obj.hasOwnProperty(i)){
newObj[i] = typeof obj[i] ==="object"?deepClone(obj[i]):obj[i];
}
}
}
return newObj
}
var newObj = deepClone(obj);
newObj.c="你好";
console.log(newObj); // {a:1,b:2,c:"你好"}
console.log(obj); //{a:1,b:2,c:[1,2]}
在循环赋值的时候,还要检测属性值是否是对象或者数组,如果是,就不断递归复制,直到得到最后基本类型。
当对象内属性很多时,递归的效率会很低,消耗资源也比较大。
引用自 https://www.cnblogs.com/shiyou00/p/6379170.html
还有一种先用JSON.stringfy()序列化,然后用JSON.parse()反序列化的快速深复刻,算是一种偷懒的快速深复制;
function cloneObj(obj){
var str, newobj = obj.constructor === Array ? [] : {};
if(typeof obj !== 'object'){
return;
} else if(window.JSON){
str = JSON.stringify(obj), //序列化对象
newobj = JSON.parse(str); //还原
} else {//如果不支持以上方法
for(var i in obj){
newobj[i] = typeof obj[i] === 'object' ? cloneObj(obj[i]) : obj[i];
}
}
return newobj;
};
另一种
function clone(Obj) {
var buf;
if (Obj instanceof Array) {
buf = []; // 创建一个空的数组
var i = Obj.length;
while (i--) {
buf[i] = clone(Obj[i]);
}
return buf;
} else if (Obj instanceof Object){
buf = {}; // 创建一个空对象
for (var k in Obj) { // 为这个对象添加新的属性
buf[k] = clone(Obj[k]);
}
return buf;
}else{
return Obj;
}
}