关于深拷贝

1.用 JSON.stringify 把对象转换成字符串,再用 JSON.parse 把字符串转换成新的对象

var targetObj = JSON.parse(JSON.stringify(copyObj))
let arr4 = JSON.parse(JSON.stringify(arr))

但是需要注意的是
(1)如果对象里有函数,函数无法被拷贝下来
(2)无法拷贝copyObj对象原型链上的属性和方法
(3)当数据的层次很深,会栈溢出,比如复杂的树形结构

2.Object.assign()拷贝

当对象中只有一级属性,没有二级属性的时候,此方法为深拷贝,但是对象中有对象的时候,此方法,在二级属性以后就是浅拷贝, Object.assign()拷贝的是属性值。假如源对象的属性值是一个对象的引用,那么它也只指向那个引用。

var obj1 = {a: 1, b: 2}
var obj2 = {A: 1, B: 2}
var Coll = Object.assign({},obj1,obj2)
obj1.a = '被修改了'
Coll // {a: 1, b: 2, A: 1, B: 2}

修改obj1.a 的属性不会影响Coll,是因为 obj.a 对应的 数字1是 基本类型,按值引用。如果obj1.a 对应引用类型的值,复制的就是这个引用类型的地址。

var obj1 = {a: {name: '小红'}, b: 2}
var obj2 = {A: 1, B: 2}
var Coll = Object.assign({},obj1,obj2)
obj1.a.name = '被修改了'
Coll  //{"a":{"name":"被修改了"},"b":2,"A":1,"B":2}

3使用递归的方式实现深拷贝

var obj1 = {a: {name: '小红'}, b: 2, arr:[1,2]}
		var obj2 = {}		
		//参数:初始值,完成值
		function deepClone(initalObj, finalObj) {    
		  var obj = finalObj || {};    
		  for (var i in initalObj) {       
			//判断是否引用类型,object,Array 的typeof检测 都是object
		    if (typeof initalObj[i] === 'object') {
		    	//递归前,判断是对象还是数字,初始化
		      obj[i] = (initalObj[i].constructor === Array) ? [] : {};            
		      //递归自己
		      arguments.callee(initalObj[i], obj[i]);
		    } else {
		    //基础类型值 直接复制
		      obj[i] = initalObj[i];
		    }
		  }    
		  return obj;
		}
		
		deepClone(obj1, obj2)
		console.log(obj2)  //{a: {name: '小红'}, b: 2, arr:[1,2]}

原理: 在浅拷贝部分的原理是一样的,如果第一层键名/下标 对应的是基础类型的值,就直接复制, 如果是引用类型的值,采用递归的方式,进入到这个引用类型的值。到了第二层,循环操作第一层的步骤。
注意: arguments.callee() 这个方法因为性能问题,在es5严格模式下禁止使用,具体原因。 解决方法很简单,直接用函数名即可。

另外如果遇到两个相互引用的对象,会出现死循环的情况
为了避免相互引用的对象导致死循环的情况,则应该在遍历的时候判断是否相互引用对象,如果是则退出循环。

改进版代码,如下:

function deepClone(initalObj, finalObj) {    
  var obj = finalObj || {};    
  for (var i in initalObj) {        
    var prop = initalObj[i];        // 避免相互引用对象导致死循环,如initalObj.a = initalObj的情况
    if(prop === obj) {            
      continue;
    }        
    if (typeof prop === 'object') {
      obj[i] = (prop.constructor === Array) ? [] : {};            
      arguments.callee(prop, obj[i]);
    } else {
      obj[i] = prop;
    }
  }    
  return obj;
}

3.jquery的$.extend

$.extend(true, obj1, obj2)

如果需要用深拷贝,第一个参数为true即可。不用则可以省略true。

var $ = require('jquery');
var obj1 = {
    a: 1,
    b: { f: { g: 1 } },
    c: [1, 2, 3]
};
var obj2 = $.extend(true, {}, obj1);
obj1.b.f === obj2.b.f; // false

4.最后一种我觉得最简单的也是比较常用的
lodash.cloneDeep()实现深拷贝。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值