基础知识:
JS对象:指向内存中某个位置的指针,指针是可变的,也就是说可以被重新赋值,所以说,复制指针,只是将两个指针指向内存中的同一地址,也可以说是地址复制。
//复制指针
var obj = { a: "123" };
var newObj = obj;
在上面代码中,对象 obj和 newObj都能随着对方的变化而变化,所以要根据实际情况来复制对象。
一、浅复制
如果要操作的对象拥有的属性都是值类型,那么可以使用扩展语法或 Object.assign()
var obj = { foo: "foo", bar: "bar" };
var newObj = { ...obj }; // Object { foo: "foo", bar: "bar" }
var newObj = Object.assign({}, obj); // Object { foo: "foo", bar: "bar" }
补充知识:Object.assign()是ES6新加的接口,主要用来合并多个JS对象
- Object.assign() 第一个参数是目标对象,后面的都是源对象。 Object.assign (target, source1,source2, source3, …);
- 如果源对象与目标对象有相同的属性名,或源对象中有相同的属性名,后面的会覆盖前边的值
- 如果参数传入的不是Object,会转成Object
- null和undefined 不能作为参数传入,因为null和undefined 不能转成Object
- 如果发生的值是一个对象,Object.assign的处理方法是直接替换,而不是添加
一个小细节注意一下:从使用效果上来看,Object.create()创建的新对象有点类似浅复制,只不过新对象和原对象是一种继承关系,而Object.assign()创建的新对象和原对象是彼此独立的。
var obj = { a: "123", b: { c: "321"}};
for(let p in obj){
newObj[p] = obj[p];
}
上述代码只进行了对对象第一层的复制,对象里引用类型则进行的是地址复制,这一操作也是浅复制
二、深复制
1、有限制的深复制(先把对象序列化为字符串,然后再将其反序列化)
var obj = { a: "123", b: "321"};
var newObj = JSON.parse(JSON.srtingify(obj));
限制:只在对象中包含可系列化值,且没有循环引用的情况下使用
日期对象不可以被序列化,JSON.parse()后为字符串而不是日期
2、限制较少的深复制(使用递归思想)
function deepCopy(obj){
var newObj = {};
for(let p in obj){
if(!(p instanceof object) || (typeof p === 'function)){
newObj[p] = objt[p];
}else{
newObj[p] = deepCopy(obj[p]);
}
}
return newObj;
}
所以可以得出一种较为通用的JS复制对象的方法:
function deepCopy(obj){
var newObj =obj.constructor === Array ? [] : {};
newObj.constructor = obj.constructor;
if(typeof obj !== 'object'){
return ;
}else if(window.JSON) { //若需考虑特殊数据类型,比如正则函数等,则去掉此else if
newObj = JSON.parse(JSON.stringify(obj));
}else {
for(let p in obj){
if(obj[p].constructor === regExp || obj[p].constructor === Date){
newObj[p] = obj[p];
}else if(typeof p === 'object'){
newObj[p] = deepCopy(obj[p]);
}else{
newObj[p] = obj[p];
}
}
}
return newObj;
}