# 关于对象(数组)的深浅克隆

let obj = {
  a: 100, // 普通数据类型
  b: [1, 2, 3, { x: 10 }, [1, 2, 3]], // 数组
  c: {
    // 对象
    x: 10,
  },
  d: /^\d+$/, // 正则表达式
};

# 浅克隆

# 常规方法

let easyCopy = function (obj) {
  let newObj = {};
  for (const key in obj) {
    if (obj.hasOwnProperty(key)) {
      newObj[key] = obj[key];
    }
  }
  return newObj;
};
let obj2 = easyCopy(obj);

解析:浅拷贝的话只能拷贝一层

# ES6 方法

let obj2 = { ...obj };

# 深克隆

# 使用 JSON 解析实现简版深克隆

let obj2 = JSON.parse(JSON.stringify(obj));

解析:该方法只能深拷贝对象里面只有普通对象和普通类型数据的对象,针对有特殊类型的值,比如 Date,RegExp,Function 等等,该方法就不能应对了,为什么呢?请看如下代码:

# Date 类型

var d = new Date();
console.log(JSON.parse(JSON.stringify(d)));
//=>输出结果为:"2020-08-19T13:45:18.729Z"
//变成了一个字符串,但是d应该是一个Date类型的对象才对!

# RegExp 类型

var r = new RegExp();
console.log(JSON.parse(JSON.stringify(r)));
//=>输出结果为:{}
//变成了一个空对象,同理,这里正确应该是一个RegExp类型的对象才对

# ...

# 使用递归方式实现深克隆

为了解决以上这个问题,我们使用递归写一个可扩展的通用性强的深拷贝的方法,祭出代码如下:

let deepCopy = function (obj) {
  if (typeof obj !== "object") {
    return obj;
  }
  if (obj === null) {
    return null;
  }
  if (obj instanceof Date) {
    return new Date(obj);
  }
  if (obj instanceof RegExp) {
    return new RegExp(obj);
  }

  // ...
  // 继续添加需要特殊处理的类型

  let newObj = new obj.constructor();
  for (const key in obj) {
    if (obj.hasOwnProperty(key)) {
      newObj[key] = deepCopy(obj[key]);
    }
  }
  return newObj;
};

obj2 = deepCopy(obj);

# 关键代码解析

看到上面的代码,你或许有疑问:为什么没有处理数组的情况呢?是不是太不严谨了?

关键代码就在这一句!

let newObj = new obj.constructor();

为什么这里不使用下面的代码呢?

let newObj = {};
// 或者
let newOjb = new Object();

这里使用对象的构造函数(constructor)创建新对象的好处在于:这样你创建的对象的类型就不会局限于 Object,就比如数组类型(Array)的我们看看,创建之后是什么?

var arr = [];
var arr1 = new arr.constructor();
//=> arr1的结果是:[]

这也就是上面 deepCopy 方法中没有考虑数组情况的原因。

Last Updated: 6/14/2022, 9:04:49 PM