zoukankan      html  css  js  c++  java
  • 深拷贝和浅拷贝

    浅拷贝实现

    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 = /(?<={)(.|
    )+(?=})/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;
            }
  • 相关阅读:
    精讲响应式WebClient第6篇-请求失败自动重试机制,强烈建议你看一看
    dubbo实战之三:使用Zookeeper注册中心
    dubbo实战之二:与SpringBoot集成
    dubbo实战之一:准备和初体验
    树莓派4B安装官方Ubuntu20 Server版(64位)
    JUnit5学习之八:综合进阶(终篇)
    纯函数
    函数式编程基本概念
    vscod使用指南
    实际使用Elasticdump工具对Elasticsearch集群进行数据备份和数据还原
  • 原文地址:https://www.cnblogs.com/yuyujuan/p/13639586.html
Copyright © 2011-2022 走看看