在本次迭代开发中,由于引用对象的原因,导致一个bug,虽然很快得到了解决,但这个问题还是比较经典的。所以就整理下关于深拷贝的问题:
对象
Object.assign
var a={name:'name'}
var b=Object.assign({},a)
var c={...a}
var d=JSON.parse(JSON.stringify(a))
console.log(a===b)//false
console.log(a===c)//false
console.log(a===d)//false
注意:
虽然Object.assign
返回的是一个新的对象,但是在数据拷贝的过程中,如果某个key
对应的value
是引用类型的对象,那么Object.assign
只会拷贝数据的引用,所以Object.assign
其实是浅拷贝
demo1
let a={item:{name:1}}
let b=Object.assign({},a)
b===a //false
b.item===a.item //true
b.item.name = 2//这里其实是首先拿到item的引用,然后修改其name属性
console.log(a.item)//{name:2}
console.log(b.item === a.item)//true
demo2
let a={item:{name:1}};
let b=Object.assign({},a);
let c=a;
console.log(b===a)//false
console.log(b.item === a.item) //true
b.item = {name:3}//由于a和b是不同的引用,占用不同的内存空间,所以这的赋值操作不影响到a,类似demo3中c的赋值操作
console.log(a.item)//{name:1}
c.item = 123//c和a是相同的引用,所以对其属性的赋值操作会映射到a.item
console.log(a.item)//123
demo3 赋值和属性操作
let a={name:1}
let c=a;
let b=a;
c = {name:'c'}//对c的重新赋值
console.log(a)//{name:1}
b.name = 'b'//操作b内存空间的属性name
console.log(a)//{name:'b'}
…
…运算符和Object.assign行为类似
let a = {name:{item:[1,2,3]}}
let b={...a}//如果有新增属性,在后面新增即可:let b ={...a,name:'neo'}
b==a // false
b.name === a.name//true
深拷贝
JSON.string and JSON.parse
clone func
jQuery.extend
//1
var newObject = JSON.parse(JSON.stringify(oldObject));
//2
function clone(obj) {
if (obj === null || typeof(obj) !== 'object' || 'isActiveClone' in obj)
return obj;
if (obj instanceof Date)
var temp = new obj.constructor(); //or new Date(obj);
else
var temp = obj.constructor();
for (var key in obj) {
if (Object.prototype.hasOwnProperty.call(obj, key)) {
obj['isActiveClone'] = null;
temp[key] = clone(obj[key]);
delete obj['isActiveClone'];
}
}
return temp;
}
// Shallow copy
var newObject = jQuery.extend({}, oldObject);
// Deep copy
var newObject = jQuery.extend(true, {}, oldObject);
数组
slice concat
let a=[1,2,3]
let b=a.slice();
let c=a.concat();//或者使用ES7 let c = [...a],转码后也是concat
console.log(a === b)//false
console.log(a === c)//false