关于对象的深浅拷贝,个人有以下几点见解:
1.深拷贝和浅拷贝只针对像Object, Array这样的引用类型数据。
2.浅拷贝是对对象引用地址进行拷贝,并没有开辟新的栈,也就是拷贝后的结果是两个对象指向同一个引用地址,修改其中一个对象的属性,则另一个对象的属性也会改变。
3.深拷贝则是开启一个新的栈,两个对象对应两个不同的引用地址,修改一个对象的属性,不会改变另一个对象的属性。
image.png image.png真-深拷贝
看着深浅拷贝,区别写法很简单,但是那个上面的深拷贝写法是有问题的。看下面案例:
var arr=[{a:1,b:2},{a:3,b:4}]
var newArr=Object.assign([],arr)
//截断数组
newArr.length=1
console.log(newArr)//[{a:1,b:2}]
console.log(arr)//[{a:1,b:2},{a:3,b:4}]
//操作newArr,这里看着对arr没影响,实际上已经挖了一个坑,下面就跳进去
newArr[0].a=123
//修改newArr[0]这个对象,也是影响了arr[0]这个对象
console.log(arr[0])//{a: 123, b: 2}
为什么会这样呢,因为Object.assign并不是深拷贝,是披着深拷贝外衣的浅拷贝。最多也是Object.assign会课拷贝第一层的值,对于第一层的值都是深拷贝,而到第二层的时候就是 复制引用。类似的情况还有,slice方法和concat方法等。要解决这个问题,就得自己封装方法!如下:
//利用递归来实现深拷贝,如果对象属性的值是引用类型(Array,Object),
//那么对该属性进行深拷贝,直到遍历到属性的值是基本类型为止。
function deepClone(obj){
if(obj === null) return null
if(typeof obj !== 'object') return obj;
if(obj.constructor===Date) return new Date(obj);
if(obj.constructor === RegExp) return new RegExp(obj);
var newObj = new obj.constructor (); //保持继承链
for (var key in obj) {
if (obj.hasOwnProperty(key)) { //不遍历其原型链上的属性
var val = obj[key];
newObj[key] = typeof val === 'object' ? arguments.callee(val) : val; // 使用arguments.callee解除与函数名的耦合
}
}
return newObj;
}
// 测试
var arr=[{a:1,b:2},{a:3,b:4}]
var newArr=deepClone(arr)
console.log(arr[0])//{a:1,b:2}
newArr[0].a=123
console.log(arr[0])//{a:1,b:2}
还有一个方法就是简单粗暴法,我现在在用的一个方法!原理很简单,就是先把对象转成字符串,再把字符串转成对象!也能实现同样效果。
var newArr2=JSON.parse(JSON.stringify(arr));
console.log(arr[0])//{a:1,b:2}
newArr2[0].a=123
console.log(arr[0])//{a:1,b:2}
jquery 中$.extend()也可以实现深拷贝
$.extend( [deep ], target, object1 [, objectN ] )
- deep
类型: Boolean
如果是true,合并成为递归(又叫做深拷贝)。- target
类型: Object
对象扩展。这将接收新的属性。- object1
类型: Object
一个对象,它包含额外的属性合并到第一个参数。- objectN
类型: Object
包含额外的属性合并到第一个参数。
参考网址:
网友评论