Js对象浅复制与深复制

js对象的复制分为浅复制深度复制两种:
浅复制得到的子对象的属性中,如果有对象或数组形式的值,则与原对象属性中的值引用的是同一个内存地址,只要有一个对象的该属性被修改,两个对象都会被影响。
而深复制就是将属性对象复制到不同的内存地址里,修改新对象,原对象不会被影响。

浅复制

先从js的数据类型入手,为什么会出现浅复制?
js的数据类型分为两种:简单类型(也叫基本数据类型)和复杂数据类型(也叫引用数据类型)。

  1. 简单数据类型:number,string,boolean,null,undefined;
  2. 复杂数据类型: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;
    }
}

引用自 https://www.cnblogs.com/zczhangcui/p/6393239.html

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值