JavaScript 开发者经常觉得“合并”(merge)两个对象很有用。更具体地说,就是把源对象所有的本地属性一起复制到目标对象上。有时候这种操作也被称为“混入”(mixin),因为目标对象通过混入源对象的属性得到了增强。
assign() 浅拷贝
ECMAScript 6 专门为合并对象提供了Object.assign()
方法。这个方法接收一个目标对象和一个或多个源对象作为参数,然后将每个源对象中可枚举(Object.propertyIsEnumerable()
返回 true)和自有(Object.hasOwnProperty()
返回 true)属性复制到目标对象。以字符串和符号为键的属性会被复制。对每个符合条件的属性,这个方法会使用源对象上的[[Get]]取得属性的值,然后使用目标对象上的[[Set]]设置属性的值。
let dest, src, result;
/**
* 简单复制
*/
dest = {};
src = { id: 'src' };
result = Object.assign(dest, src);
// Object.assign 修改目标对象
// 也会返回修改后的目标对象
console.log(dest === result); // true
console.log(dest !== src); // true
console.log(result); // { id: src }
console.log(dest); // { id: src }
/**
* 多个源对象
*/
dest = {};
result = Object.assign(dest, { a: 'foo' }, { b: 'bar' });
console.log(result); // { a: foo, b: bar }
/**
* 获取函数与设置函数
*/
dest = {
set a(val) {
console.log(`Invoked dest setter with param ${val}`);
}
};
src = {
get a() {
console.log('Invoked src getter');
return 'foo';
}
};
Object.assign(dest, src);
// 调用 src 的获取方法
// 调用 dest 的设置方法并传入参数"foo"
// 因为这里的设置函数不执行赋值操作
// 所以实际上并没有把值转移过来
console.log(dest); // { set a(val) {...} }
Object.assign()实际上对每个源对象执行的是浅复制。如果多个源对象都有相同的属性,则使用最后一个复制的值。此外,从源对象访问器属性取得的值,比如获取函数,会作为一个静态值赋给目标对象。换句话说,不能在两个对象间转移获取函数和设置函数。
注意 浅拷贝只是在更深层次(比如对象)进行地址传递,而在简单的属性上依然是拷贝
var obj = {
id: 1, //此项修改不会引起拷贝对象改变
name: 'andy', //这一项也一样
msg: {
age: 18 //修改对象里的属性时,拷贝对象只是拷贝对象地址,所以会同时修改
}
};
var o = {};
Object.assign(o, obj);
console.log(o);
o.msg.age = 20; //拷贝的对象公用同一个地址,改变会一起改变
o.id=3; //只是o对象里id属性修改
o.name="some" //与上面相同,只有o对象里属性改变
console.log(obj);
浅拷贝后修改拷贝对象的属性不会影响获得拷贝对象 (当然只是简单属性,不涉及拷贝对象里包含的对象里的属性)
定义一个递归函数来进行深拷贝
function deepCopy(newobj,oldobj) {
for (const k in oldobj) {
let item =oldobj[k];
if (item instanceof Array) {
newobj[k]=[];
deepCopy(newobj[k],item)
}else if(item instanceof Object){
newobj[k]={};
deepCopy(newobj[k],item)
}else{
newobj[k]=item;
}
}
}
//使用函数
obj={
name:'other',
sex:'nan',
num:[1,5,3,4,8,6,[5,4,8,6,2,1]],
score:{
some:0
}
};
o={};
deepCopy(o,obj)
console.log(o);
通过JSON来进行深拷贝
var targetObj = JSON.parse(JSON.stringify(copyObj))
let arr4 = JSON.parse(JSON.stringify(arr))
缺点:
(1)如果对象里有函数,函数无法被拷贝下来
(2)无法拷贝copyObj对象原型链上的属性和方法
(3)当数据的层次很深,会栈溢出