深拷贝、浅拷贝
深、浅拷贝都是针对引用类型而言的,浅拷贝只是复制对象的引用,拷贝后的对象和原对象只要有一个发生变化,另一个也会相应变化,而深拷贝则是真正的对对象的拷贝。
【浅拷贝】
只是复制对象的引用,并未实现真正的复制。 常见实现浅拷贝的方法有一下几种:
- 简单使用=赋值
- 使用Object.assign()
- 使用展开运算符(...)
var arr = [1,2,3];
var obj = {a:'a', b:[1,2], c:{cc:'cc'}};
var cloneArr = arr;
var cloneObj = obj;
cloneArr.push(4);
cloneObj.a = 'aaa';
console.log(arr); // [1, 2, 3, 4]
console.log(cloneArr); // [1, 2, 3, 4]
console.log(obj); // {a:'aaa', b:[1,2], c:{cc:'cc'}}
console.log(cloneObj); // {a:'aaa', b:[1,2], c:{cc:'cc'}}
【深拷贝】
实现了真正的复制,拷贝的对象与原对象完全隔离,互不影响。 实现深拷贝的方法主要有两种:
- 利用JSON中的parse和stringify
- 利用递归来实现每一层重新创建对象并赋值
(一) JSON中是parse和stringify
var arr = [1,2,3];
var obj = {a:'a', b:[1,2], c:{cc:'cc'}};
var cloneArr = JSON.parse(JSON.stringify(arr));
var cloneObj = JSON.parse(JSON.stringify(obj));
cloneArr.push(4);
cloneObj.a = 'aaa';
cloneObj.b.push(3);
cloneObj.c = 'ccc';
console.log(arr); // [1, 2, 3]
console.log(cloneArr); // [1, 2, 3, 4]
console.log(obj); // {a:'a', b:[1,2], c:{cc:'cc'}}
console.log(cloneObj); // {a:'aaa', b:[1,2,3], c:{cc:'ccc'}}
弊端:对于一些复杂的引用类型,就会出现问题
var obj = {
name: 'Tom',
sayName: function(){
console.log(this.name)
}
}
var cloneObj = JSON.parse(JSON.stringify(obj));
console.log(obj); // {name: "Tom", sayName: ƒ}
console.log(cloneObj); // {name: "Tom"}
(二) 递归实现
利用递归实现深拷贝的思想是每一层都重新创建对象并赋值
function deepClone(source){
const targetObj = source.constructor === Array ? [] : {}; // 判断复制的目标是数组还是对象
for(let keys in source){
if(source.hasOwnProperty(keys)){ // 判断属性是否存在于实例中
if(source[keys] && typeof source[keys] === 'object'){ // 如果值是对象,就递归一下
targetObj[keys] = source[keys].constructor === Array ? [] : {};
targetObj[keys] = deepClone(source[keys]);
}else{ // 如果不是,就直接赋值
targetObj[keys] = source[keys];
}
}
}
return targetObj;
}
// 测试
var obj = {
name: 'Tom',
sayName: function(){
console.log(this.name)
}
}
var cloneObj = deepClone(obj);
console.log(obj); // {name: "Tom", sayName: ƒ}
console.log(cloneObj); // {name: "Tom", sayName: ƒ}
JavaScript中的有的方法也能实现拷贝,比如:concat()和slice(),ES6中的Object.assgin()和...展开运算符。这里就不一一测试了,直接给出结论吧。
concat 只是对数组的第一层进行深拷贝 slice 只是对数组的第一层进行深拷贝 Object.assign() 拷贝的是属性值。假如源对象的属性值是一个指向对象的引用,它也只拷贝那个引用值 ... 实现的是对象第一层的深拷贝。后面的只是拷贝的引用值