展开运算符...和Object.assign都是浅拷贝,常见的js方法如slice也是浅拷贝,那如何实现深拷贝呢?
// 需要递归拷贝 
function deepClone(obj) {
  // 如果传递的是null 那就不处理
  // 函数没有引用关系
  if (typeof obj !== 'object') return obj;
  if (obj == null) return null;
  // 处理日期和正则
  if (obj instanceof RegExp) return new RegExp(obj);
  if (obj instanceof Date) return new Date(obj);
   // Object.prototype.toString.call(obj) === '[object Array]', 这么判断保留不了继承关系
  let instance = new obj.constructor(); // 看当前实例的constructor
  // 实现深拷贝
  //for...in循环是 遍历对象的每一个可枚举属性,包括原型链上面的可枚举属性,
   for (let key in obj) {
            if(obj.hasOwnProperty(obj[key])) {
                instance[key] = typeof obj[key] === 'object' ? deepClone(obj[key]) : obj[key]
            }
        }
  return instance;
}
// 函数不需要重新拷贝
let obj = { a: { a: 1 } }
let newObj = deepClone(obj);
obj.a.a = 2;
console.log(newObj);
复制代码思路是首先判断obj类型,null、Date对象,数组、正则、以及对象的typeof结果都是oobject,
需要单独分情况考虑。
对于null、Date对象以及正则,我们直接返回数值就可以了
对于数组,我们没有直接返回,因为数组可能有继承关系,需要保留继承关系,这个需要注意。
1)判断数组类型我们没用Object.prototype.toString.call(obj),因为它保留不了继承关系。
举例如下:
var t = [1,2]
t.__proto__={a:1}
Object.prototype.toString.call(t) ----> // "[object Array]"
t.constructor ----->  // ƒ Object() { [native code] }
new t.constructor() --> objcet
总结
实现深拷贝的几个要点:
- 需要递归拷贝。
- 需要判断类型
- 无法拷贝proto