深拷贝和浅拷贝

浅拷贝实现

Object.assign

Object.assgin() 拷贝的是对象的属性的引用,而不是对象本身。

 concat()

concat用于浅拷贝数组。

slice

只能拷贝一层对象。如果有对象的嵌套,那么浅拷贝将无能为力

  

...展开运算符

 

 

手动实现

const shallowClone = (target) => {
  if (typeof target === 'object' && target !== null) {
    const cloneTarget = Array.isArray(target) ? []: {};
    for (let prop in target) {
      if (target.hasOwnProperty(prop)) {
          cloneTarget[prop] = target[prop];
      }
    }
    return cloneTarget;
  } else {
    return target;
  }
}

深拷贝

JSON.parse(JSON.stringify())

JSON.parse(JSON.stringify())可以实现深拷贝,但是存在很多问题:
  • 无法解决循环引用的问题;
  • 无法拷贝特殊的对象:RegExp、Date、Set、Map等;
  • 无法拷贝函数

手动实现

 const getType = obj => Object.prototype.toString.call(obj);

        const isObject = (target) => (typeof target === 'object' || typeof target === 'function') && target !== null;

        const canTraverse = {
            '[object Map]': true,
            '[object Set]': true,
            '[object Array]': true,
            '[object Object]': true,
            '[object Arguments]': true,
        };
        const mapTag = '[object Map]';
        const setTag = '[object Set]';
        const boolTag = '[object Boolean]';
        const numberTag = '[object Number]';
        const stringTag = '[object String]';
        const symbolTag = '[object Symbol]';
        const dateTag = '[object Date]';
        const errorTag = '[object Error]';
        const regexpTag = '[object RegExp]';
        const funcTag = '[object Function]';

        const handleRegExp = (target) => {
            const { source, flags } = target;
            return new target.constructor(source, flags);
        }

        const handleFunc = (func) => {
            // 箭头函数直接返回自身
            if (!func.prototype) return func;
            const bodyReg = /(?<={)(.|\n)+(?=})/m;
            const paramReg = /(?<=\().+(?=\)\s+{)/;
            const funcString = func.toString();
            // 分别匹配 函数参数 和 函数体
            const param = paramReg.exec(funcString);
            const body = bodyReg.exec(funcString);
            if (!body) return null;
            if (param) {
                const paramArr = param[0].split(',');
                return new Function(...paramArr, body[0]);
            } else {
                return new Function(body[0]);
            }
        }

        const handleNotTraverse = (target, tag) => {
            const Ctor = target.constructor;
            switch (tag) {
                case boolTag:
                    return new Object(Boolean.prototype.valueOf.call(target));
                case numberTag:
                    return new Object(Number.prototype.valueOf.call(target));
                case stringTag:
                    return new Object(String.prototype.valueOf.call(target));
                case symbolTag:
                    return new Object(Symbol.prototype.valueOf.call(target));
                case errorTag:
                case dateTag:
                    return new Ctor(target);
                case regexpTag:
                    return handleRegExp(target);
                case funcTag:
                    return handleFunc(target);
                default:
                    return new Ctor(target);
            }
        }
        // 解决循环引用:创建一个Map,记录下已经拷贝过的对象,如果说已经拷贝过,那直接返回。
        const deepClone = (target, map = new Map()) => {
            if (!isObject(target))
                return target;
            let type = getType(target);
            let cloneTarget;
            if (!canTraverse[type]) {
                // 处理不能遍历的对象
                return handleNotTraverse(target, type);
            } else {
                // 这波操作相当关键,可以保证对象的原型不丢失!
                let ctor = target.constructor;
                cloneTarget = new ctor();
            }

            if (map.get(target))
                return target;
            map.set(target, true);

            if (type === mapTag) {
                //处理Map
                target.forEach((item, key) => {
                    cloneTarget.set(deepClone(key, map), deepClone(item, map));
                })
            }

            if (type === setTag) {
                //处理Set
                target.forEach(item => {
                    cloneTarget.add(deepClone(item, map));
                })
            }

            // 处理数组和对象
            for (let prop in target) {
                if (target.hasOwnProperty(prop)) {
                    cloneTarget[prop] = deepClone(target[prop], map);
                }
            }
            return cloneTarget;
        }

 

posted on 2020-09-09 16:40  紅葉  阅读(198)  评论(0编辑  收藏  举报