对数据进行备份是一个常见的问题。那么什么是深拷贝浅拷贝呢?
我们都知道js的数据类型有值类型和引用类型。
- 值类型:通过赋值即可实现数据备份
- 引用类型:由于变量中保存的只是指向数据值的指针,因而若简单复制变量,那么若改变变量,原对象也会跟着改变,这就是浅拷贝。所以深拷贝指的自然就是另外开辟一块内存保存对象的值,这样即使改变了拷贝后的数据,原数据也不会改变。
浅拷贝
普通赋值
function clone(copyObj) {
var obj = {};
for ( var i in copyObj) {
obj[i] = copyObj[i];
}
return obj;
}
var x = {
a: 1,
b: { f: { g: 1 } },
c: [ 1, 2, 3 ]
};
var y = clone(x);
y.c.push(4);
console.log(x.c); // 1,2,3,4
console.log(y.b.f === x.b.f); // true
通过改变y的属性值,x的属性值也会相应改变。
ES6 中Object.assign()
用于对象的合并,将源对象(source)的所有可枚举属性,复制到目标对象(target)。该方法是一个浅拷贝方法。
var x = {
a: 1,
b: { f: { g: 1 } },
c: [ 1, 2, 3 ]
};
var y = Object.assign({}, x);
console.log(y.b.f === x.b.f); // true
Array中的slice和concat方法
slice和concat虽然都是会返回一个新数组,但是它们也是浅拷贝。对于数组中属性值为引用类型的属性只是复制了指针。
let array = [1, [1,2,3], {name:"array"}];
let array_shallow = array;
let array_concat = array.concat();
let array_slice = array.slice(0);
console.log(array === array_shallow); //true
console.log(array === array_slice); //false
console.log(array === array_concat); //false
array_concat[1][0] = 5;
console.log(array[1]); //[5,2,3]
console.log(array_slice[1]); //[5,2,3]
array_slice[2].name = "array_slice";
console.log(array[2].name); //array_slice
console.log(array_concat[2].name); //array_slice
由例子可知,对于引用类型,若是改变拷贝后的值,原值也会被改变。
另外再添加一个小知识点:slice的参数可以是负数,若是负数,则用数组长度加上该数来确定相应的位置。若结束位置小于起始位置,不会报错,而是返回空数组。
深拷贝
JSON
JSON对象的parse方法可以将JSON字符串反序列化成对象,stringify方法可以将对象序列化成JSON字符串。
let source = {
name:"source",
child:{
name:"child"
},
fun: function () {
console.log('function');
},
reg: new RegExp("e")
};
let target = JSON.parse(JSON.stringify(source));
console.log(target); //Object {name: "source", child: Object, reg: Object}
console.log(target.fun); // undefined
console.log(target.reg); // Object {}
target.name = "target"; //改变target的name属性
console.log(source.name); //source
console.log(target.name); //target
target.child.name = "target child"; //改变target的child
console.log(source.child.name); //child
console.log(target.child.name); //target child
由例子可知,对于简单的对象使用JSON方法可以实现深拷贝。
但是它还有很多缺点:
- 对于正则表达式、函数等无法进行深拷贝
- 这样做的深拷贝会抛弃对象的constructor。
不管这个对象原来的构造函数是什么,在深拷贝之后都会变成Object。 - 当遇到层级较深,且序列化对象不完全符合JSON格式时,使用JSON的方式进行深拷贝就会出现问题。
使用递归
。。。。。持续更新中