浅拷贝与深拷贝学习笔记

101 阅读17分钟

 以下是浅拷贝与深拷贝的各种方法及其区别:

测试数据:

  const target = {      a: '1',      e: [1, 2, 3, 4, [5, 6, [7, 8, [9]]]],      b: {        c: [{          h: '1',          i: '2'        }],        d: {          f: {            g: '4'          }        }      },      j: null,      k: undefined,      l: function () {        console.log('l');      },      date: new Date(),      reg: /[A-Z]/g,    }

所需知识点:

typeof [],null,object 皆为object
hasOwnProperty:过滤原型属性,只能获取自有属性
对象遍历:
1、for in可以遍历可枚举属性,包括原型链上的属性;
2、Object.keys返回一个由对象可枚举属性组成的数组,不包括原型属性;
3、Object.getOwnProperty 返回对象的自有属性数组,包括可枚举的和不可枚举的,不包括原型属性
数组遍历:
for in 输出数组的index,即'0','1','2','3','4','5'....
Object.keys 同上
Object.getOwnProperty 输出'0','1','2','3'...,'length'
浅克隆
    const shallClone = (target) => {      if (typeof target === 'object' && target !== null) {        const cloneTarget = Array.isArray(target) ? [] : {}        for (prop in target) {          if (target.hasOwnProperty(prop)) {            cloneTarget[prop] = target[prop]          }        }        return cloneTarget      } else {        return target      }    }    // console.log('shallClone', shallClone(target));    // target.b = {} //此层拷贝的是值    // target.b.c = {} //此层拷贝的是引用    // target.b.c.h = '7' //此层拷贝的是引用
经测试,shallClone方法除函数拷贝后是个空函数外基本上可以成功拷贝,但是对象值的对象值只拷贝了引用,而不是值,即对象只拷贝了一层。

深克隆

1、第一种方法

    function deepClone(target) {      if (typeof target === 'object' && target !== null) {        const cloneTarget = Array.isArray(target) ? [] : {}        for (let prop in target) {          if (target.hasOwnProperty(prop)) {            cloneTarget[prop] = deepClone(target[prop])          }        }        return cloneTarget      } else {        return target      }    }    console.log('deepClone', deepClone(target));    // target.b = {} //此层拷贝的是值    // target.b.c = {} //此层拷贝的是值    // target.b.c.h = '7' //此层拷贝的是值

运行结果:

经测试,deepClone方法可以拷贝整个对象的值,而不是引用,但是date格式和正则表达式拷贝失败,结果为空对象,函数拷贝失败,为空函数。

2、第二种方法

    const isObject = (target) => (typeof target === 'object') && target !== null;    function deepClone2(target, map = new Map()) {      Date.prototype.clone = function () {        return new Date(this.valueOf());      }      RegExp.prototype.clone = function () {        var pattern = this.valueOf();        var flags = '';        flags += pattern.global ? 'g' : '';        flags += pattern.ignoreCase ? 'i' : '';        flags += pattern.multiline ? 'm' : '';        return new RegExp(pattern.source, flags);      };      // 先判断该引用类型是否被 拷贝过      if (map.get(target)) {        return target;      }      // 检测当前对象target是否与 正则、日期格式对象匹配      if (eval(target) instanceof RegExp || target instanceof Date) {        console.log(target.clone())        return target.clone()      }      if (isObject(target)) {        map.set(target, true); // 为循环引用的对象做标记        const cloneTarget = Array.isArray(target) ? [] : {};        for (let prop in target) {          if (target.hasOwnProperty(prop)) {            cloneTarget[prop] = deepClone2(target[prop], map);          }        }        return cloneTarget;      } else {        return target;      }    }    console.log('deepClone2', deepClone2(target));    // target.b = {} //此层拷贝的是值    // target.b.c = {} //此层拷贝的是值    // target.b.c.h = '7' //此层拷贝的是值
运行结果:

经测试,除函数外都能拷贝成功。

3、第三种方法

    console.log('deepClone3', deepClone3(target));    // target.b = {} //此层拷贝的是值    // target.b.c = {} //此层拷贝的是值    // target.b.c.h = '7' //此层拷贝的是值
运行结果:

经测试,除开undefined值和正则,函数不能拷贝,其他情况都能拷贝。