1. 深拷贝和浅拷贝简单理解
浅拷贝的对象若包含子对象,当新的对象对子对象发生改变时则会使原对象子对象一同改变,若新的对象只改变第一层的数据,则源对象不会改变。
换句话说:浅拷贝过来的数据只有第一层数据不是共享的,第二层乃至第三层的数据和源对象是共享的。而深拷贝是和源对象没有任何共享的
。
- 浅拷贝:
将原对象或原数组的引用直接赋给新对象或新数组,新对象或数组只是原对象的一个引用 - 深拷贝:
创建一个新的对象和数组,将原对象的各项属性的“值”(数组的所有元素)拷贝过来, 是“值”而不是“引用”。 - 深拷贝的要求程度:
是仅“深”拷贝第一层级的对象属性或数组元素,还是递归拷贝所有层级的对象属性和数组元素? - 怎么检验深拷贝成功:
改变任意一个新对象/数组中的属性/元素, 都不改变原对象/数组。
2. 深拷贝的实现
2.1 弱鸡版
let a = [1, '2', 'stu', 'ku', 'pu'];
let b = JSON.parse(JSON.stringify(a));
a[0] = 9
console.log(a); // [ 9, '2', 'stu', 'ku', 'pu' ]
console.log(b); // [ 1, '2', 'stu', 'ku', 'pu' ]
2.2 递归调用函数版
function deepClone(obj) {
if (obj == null) return null; //直接退出
if(obj instanceof Date) return new Date(obj);//如果拷贝的是Date日期对象 那么直接返回一个新的日期就好啦
if(obj instanceof RegExp) return new RegExp(obj); //如果传进来的参数是正则表达式,那就返回一个正则表达式
if(typeof obj !== "object") return obj; // 如果是非对象,直接返回
let newObj = obj instanceof Array ? [] : {}; // 验证传递过来的参数是数组还是对象,从而判断创建新的数组或对象
// 如果是对象,则for in遍历这个对象
for(let key in obj) { // key就是对象的每一个可枚举的属性名
// 如果obj是对象,则继续递归深拷贝这个对象,否则返回
newObj[key] = typeof obj[key] === "object" ? deepClone(obj[key]) : obj[key];
}
return newObj;
}
let a = [1, 2, 3, 5, "a", "SongTang", [1, 2], {cost: 65}, null];
let c = a;
let b = deepClone(a);
a[6][0] = 10;
a[2] = 2;
console.log(a); // [1, 2, 2, 5, "a", "SongTang", [10, 2], {cost: 65}, null];
console.log(b); // [1, 2, 3, 5, "a", "SongTang", [1, 2], {cost: 65}, null];
console.log(c); // 和 a一样
//结论: 成功实现了深拷贝