前端深拷贝的那点事

117 阅读1分钟

为什么要深拷贝

因为js有引用数据类型,引用数据类型是以地址的形式存在数据中。直接赋值后修改其值,所有复制的值都会变。

利用JSON转一下不香么?

JSON.parse(JSON.stringify(data))

日期、NAN、undefined、函数、正则等有问题

利用扩展运算符不香么?

{...obj}
[...arr]

不能深度拷贝

手写深拷贝

随手拈来的版本

除了object的typeof为object外,null的typeof也为object

function copy(target) {
  if (target && typeof target === 'object') {
    if (target instanceof Array) {
      let arr = [];
      target.forEach((item, index) => {
        arr[index] = copy(item);
      });
      return arr;
    }
    let obj = {};
    for (let key in target) {
      obj[key] = copy(target[key]);
    }
    return obj;
  }
  return target;
}

因为在typeof target === 'object‘里只判断了数组类型,所以上述方法只能复制引用数据类型为对象和数组的数据。

进阶版本

array、date、regExp等数据的typeof也为object,这里借用Object.prototype.toString获取准确的数据类型

function copy(target) {
  switch (Object.prototype.toString.call(target).slice(8, -1)) {
    case 'Object':
      let obj = {};
      for (let key in target) {
        obj[key] = copy(target[key]);
      }
      return obj;
    case 'Array':
      let arr = [];
      target.forEach((item, index) => {
        arr[index] = copy(item);
      });
      return arr;
    default:
      return target;
  }
}

当然上面的精确判断对象是对象的方法也可以换成别的,比如 target.constructor === Object