JS之手写深拷贝

30 阅读1分钟

废话不多说,直接代码伺候:

    function deepClone(obj){
        // 先判断不是引用数据类型的
        if(typeof obj !== 'object' || !obj)return obj;
        // 接下来判断引用数据类型
        // Object.prototype.toString.call()判断更准确具体
        let type = Object.prototype.toString.call(obj)
        let typeObject = '[object Object]'
        // 数组
        if(typeof obj === 'object' && obj instanceof Array){
            // 创建一个实例用来存储数据
            // let result = new Array()
            let result = new obj.constructor()
            for (let key in obj) {
                result[key] = deepClone(obj[key]);
            }
            return result
        // 对象
        }else if(type === typeObject){
            // let result = new Object()
            let result = new obj.constructor()
            for (let key in obj) {
                result[key] = deepClone(obj[key]);
            }
            return result
        }
        // 其他类型判断 ......
    }
    // 测试代码
    const obj = {
        name: "jack",
        arr: [1, 2, 3],
        arrObj: [{ n: 1 }, { m: 2 }],
        fn: function () {},
        nul: null,
        undef: undefined,
      };
   let newObj = deepClone(obj)
   console.log(newObj)

进阶版且解决环形对象

    const obj = {
        name: "jack",
        age: 18,
        bool: true,
        f: function () {},
        und: undefined,
        nul: null,
        hobby: { sport: "篮球" },
        map: new Map(),
        set: new Set(),
        date: new Date(),
        zz: /a/,
      };
      // 遇到环形时则会无限递归,导致栈内存溢出
      const obj2 = { to: obj };
      obj.to = obj2;

      // 使用 WeakMap 解决强引用,处理环形对象带来的递归栈内存溢出
      let cache = new WeakMap();

      function deepClone(obj) {
        // 判断基本类型 undefined null function
        if (typeof obj !== "object" || !obj) return obj;

        // 处理当发现缓存中有 obj 的 key 时,直接读取
        if (cache.has(obj)) {
          return cache.get(obj);
        }
        let result;
        if (obj instanceof Map) {
          result = new Map();
          cache.set(obj, result);
          obj.forEach((val, key) => {
            result.set(deepClone(key), deepClone(val));
          });
        } else if (obj instanceof Set) {
          result = new Map();
          cache.set(obj, result);
          obj.forEach((val) => {
            result.add(deepClone(val));
          });
        } else if (obj instanceof Date || obj instanceof RegExp) {
          result = new obj.constructor(obj);
          cache.set(obj, result);
        } else {
          result = new obj.constructor();
          cache.set(obj, result);
          for (let key in obj) {
            result[key] = deepClone(obj[key]);
          }
        }
        return result;
      }

      const x = deepClone(obj);
      console.log(x);