关于javascript:深入09-深浅拷贝

41次阅读

共计 14443 个字符,预计需要花费 37 分钟才能阅读完成。

导航

[[深刻 01] 执行上下文](https://juejin.im/post/684490…
[[深刻 02] 原型链](https://juejin.im/post/684490…
[[深刻 03] 继承](https://juejin.im/post/684490…
[[深刻 04] 事件循环](https://juejin.im/post/684490…
[[深刻 05] 柯里化 偏函数 函数记忆](https://juejin.im/post/684490…
[[深刻 06] 隐式转换 和 运算符](https://juejin.im/post/684490…
[[深刻 07] 浏览器缓存机制(http 缓存机制)](https://juejin.im/post/684490…
[[深刻 08] 前端平安](https://juejin.im/post/684490…
[[深刻 09] 深浅拷贝](https://juejin.im/post/684490…
[[深刻 10] Debounce Throttle](https://juejin.im/post/684490…
[[深刻 11] 前端路由](https://juejin.im/post/684490…
[[深刻 12] 前端模块化](https://juejin.im/post/684490…
[[深刻 13] 观察者模式 公布订阅模式 双向数据绑定](https://juejin.im/post/684490…
[[深刻 14] canvas](https://juejin.im/post/684490…
[[深刻 15] webSocket](https://juejin.im/post/684490…
[[深刻 16] webpack](https://juejin.im/post/684490…
[[深刻 17] http 和 https](https://juejin.im/post/684490…
[[深刻 18] CSS-interview](https://juejin.im/post/684490…
[[深刻 19] 手写 Promise](https://juejin.im/post/684490…
[[深刻 20] 手写函数](https://juejin.im/post/684490…

[[react] Hooks](https://juejin.im/post/684490…

[[部署 01] Nginx](https://juejin.im/post/684490…
[[部署 02] Docker 部署 vue 我的项目](https://juejin.im/post/684490…
[[部署 03] gitlab-CI](https://juejin.im/post/684490…

[[源码 -webpack01- 前置常识] AST 形象语法树](https://juejin.im/post/684490…
[[源码 -webpack02- 前置常识] Tapable](https://juejin.im/post/684490…
[[源码 -webpack03] 手写 webpack – compiler 简略编译流程](https://juejin.im/post/684490…
[[源码] Redux React-Redux01](https://juejin.im/post/684490…
[[源码] axios ](https://juejin.im/post/684490…
[[源码] vuex ](https://juejin.im/post/684490…
[[源码 -vue01] data 响应式 和 初始化渲染 ](https://juejin.im/post/684490…

前置常识

堆栈

  • stack 栈

    • <font color=red> 栈区 </font> 蕴含了:<font color=red> 变量的标识符 </font> 和 <font color=red> 变量的值 </font>
    • 栈区:

      • 指的是内存中的栈内存
      • 根本类型的数据(值类型数据)保留在栈中
    • 比拟

      • <font color=red> 根本类型数据的比拟是(值)得比拟 </font>
      • <font color=red> 根本类型的数据(不可变),不能增加属性和办法 </font>
  • heap 堆

    • 堆区

      • 援用类型的数据保留在栈和堆中
      • 栈区保留:<font color=red> 变量标识符 </font> 和 指向堆内存中对象的 <font color=red> 指针 </font>
      • 堆区保留:具体的对象数据
    • 比拟

      • <font color=red> 援用类型数据的比拟是(援用)的比拟 </font>
      • <font color=red> 援用类型的数据(可变),能够增加属性和办法 </font>

数据类型

  • 根本数据类型(值类型):number,string,boolean,null,undefined,symbol
  • 援用类型的数据:object,array,function 等
  • 区别:

    • <font color=red> 根本类型没有属性和办法,大小固定,保留在栈区 </font>
    • <font color=red> 援用类型有属性和办法,大小不固定,保留在栈区和堆区,栈中保留指向堆中数据的地址 </font>

数据类型的案例

援用类型和原始类型的案例

var a = 1 // 根本类型的数据
var b = {name: 'woow_wu7'} // 援用类型的数据
var aa = a // a 和 aa 是不同的数据
var bb = b // b 和 bb 指向堆中的同一份数据,批改堆中数据,b 和 bb 的指向没变,则援用的值也会跟着扭转
a = 2
b.name = 'wang'

console.log(a, aa, 'a 和 aa 是不同的数据') // 扭转后不等
console.log(b.name, bb.name, 'b 和 bb 两个变量中的指针 => 都同时指向了同一个堆内存中的数据') // 扭转后相等
console.log(b === bb) // true,阐明两个变量指向了同一个堆内存

Map 数据结构

  • Object 对象的 key 只能是字符串

    • 字符串 - 值 对应
  • Map 数据结构的 key 能够是任意类型

    • 值 - 值 对应
  • <font color=red>Map 相似于对象,也是 key,value 的键值对的汇合 </font>
  • Map 是一种更欠缺的 hash 构造实现,如果你须要键值对的数据结构,Map 比 Object 更适合
  • Map.prototype.set(key, value) // key 能够是任意类型
  • Map.prototype.get(key)
  • Map.prototype.has(key) // 返回布尔值
  • Map.prototype.delete(key) // 删除某个键,但返回布尔值,示意是否删除胜利
  • Map.prototype.clear() // 革除所有成员,没有返回值
  • Map.prototype.keys() values() entries() forEach()
  • <font color=red>Map 构造函数能够承受数组为参数,成员必须是一个个示意键值对的数组 </font>
  • <font color=red>Map 能保障对象 key 的唯一性 </font>

    
    const mapArrKey = [1,2];
    const mapKeyAddress = ['chongqign']
    
    const mapInstance = new Map([['name', 'woow_wu'],
    [[1,2], 20],
    [mapArrKey, 20],
    [{age: 20}, {age: 20}],
    ])
    console.log(mapInstance, 'mapInstance')
    console.log(mapInstance.size, 'size') // 4
    console.log(mapInstance.get(mapArrKey), 'Map.prototype.get(key) => key 是一个数组')
    console.log(mapInstance.get([1,2]), 'Map.prototype.get(key)') // undefined 必须是同一个数组
    
    mapInstance.set(mapKeyAddress, '地址')
    console.log(mapInstance.get(mapKeyAddress))
    console.log(mapInstance.has(mapKeyAddress), 'Map.prototype.has(key) => key 是否存在,布尔值') // true
    console.log(mapInstance.delete(mapKeyAddress), 'Map.prototype.delete(key) => 删除键,返回布尔值,示意是否删除胜利') // true
    console.log(mapInstance.get(mapKeyAddress)) // undefined
    console.log(mapInstance.clear(), 'Map.prototype.clear() => 删除所有键,没有返回值')
    console.log(mapInstance)

Reflect

  • 操作对象的 api
  • reflect:反映,反射的意思
  • Reflect.get(target, name, receiver)

    • 获取 target 对象的 name 属性,如果没有该属性返回 undefined
    • 如果 name 属性部署了 getter 函数,getter 函数中的 this 指向 receiver 参数对象
    • 如果 target 参数不是对象,Reflect.get()会报错
  • Reflect.set(target, name, value, receiver)

    • 设置 target 对象的 name 属性为 value
    • 如果 name 属性部署了 settter 函数,setter 函数中的 this 指向 receiver 参数对象
  • Reflect.deleteProperty(obj, name)

    • 删除 obj 的 name 属性
    • 相当于: delete obj.name
  • Reflect.constructor(target, args)

    • 执行构造函数 target,传入 target 构造函数的参数是 args
    • 如果 target 不是函数,就会报错
  • Reflect.getPrototypeOf(obj)

    • 相等于:Object.getPrototypeOf(obj)
  • Reflect.setProrotypeOf(obj, prototypeObj)
  • Reflect.apply(func, thisArg, args)

    • 等于:Function.prototype.apply.call(func, thisArg, arges)
  • <font color=red>Reflect.ownKeys(target)</font>

    • 返回对象参数的所有属性,留神:包含 Symbol 类型的属性
    • 等同于 Object.getOwnPropertyNames 与 Object.getOwnPropertySymbols 之和
    • 包含 symbol 类型的属性!!!

运算符的联合性

  • <font color=red> 一元运算符,三元运算符,赋值运算符是右联合,其余的都是左联合 </font>
  • 三元运算符是右联合:即从右向左算,先算左边的三元表达式,再算右边的三元表达式

    三元运算符右联合
    
    let name = null
  • === true ? name = ‘wang’ : 1 < 0 ? name = ‘zhang’ : name = ‘woow_wu7’;
    // 相当于:1 === true ? name = ‘wang’ : (1 < 0 ? name = ‘zhang’ : name = ‘woow_wu7’)

    console.log(name, ‘name’)
    // ‘woow_wu7’
    // 1 === true // false,类型不一样都是 false

typeof 返回值

  • typeof 能够用来判断根本数据类型,返回值是字符串
  • typeof 不能辨别对象类型的数据:如对象还是数组
  • <font color=red>typeof 的返回值一共有 7 种类型 </font>

  • 返回值有(7 种):number,string,boolean,undefined,symbol,function,object
  • 根底数据类型(6 种):number,string,boolean,undefined,symbol,null

    typeof NaN ———————- ‘number’
    typeof Symbol() —————– ‘symbol’
    typeof function(){} ————- ‘function’
    typeof [] ———————- ‘object’
    typeof {} ———————- ‘object’
    typeof null ——————— ‘object’

浅拷贝和深拷贝的区别

  • <font color=red> 浅拷贝是只进行一层拷贝,深拷贝是拷贝所有层级,直到属性对应的值是原始数据为止 </font>
  • 浅拷贝

    • 创立一个新对象(创始一个新的堆空间),该新对象有着原始对象属性值的准确拷贝
    • 属性值是根本类型,拷贝的就是根本类型的值(即拷贝的是值,互不烦扰
    • 属性值是援用类型,拷贝的就是指向堆内存的指针(即拷贝的是指针,互相烦扰
  • 深拷贝

    • 在堆内存中创立一个新空间,把对象实现的拷贝到新空间中,互相独立,互不烦扰

浅拷贝和赋值的区别

之所以不易辨别浅拷贝和赋值,是因为拷贝后个别都随同者赋值

  • 赋值:两个变量对象的指针,指向同一个堆内存中的对象数据,不会开翻新的堆空间
  • 浅拷贝:<font color=red> 创始一个新的堆内存空间(即创立一个新对象),新对象是对原始对象的一个准确拷贝,属性是根本类型的值拷贝的就是根本类型的值,如果属性是援用类型的值,拷贝的就是堆内存的指针 </font>
  • `

    用 Reflect 解决 Symbol 类型数据的复制

    var objComplex = {
    address: {
    city: ‘chongqing’,
    town: ‘jiazhou’,
    },
    score: [100, 200],
    }
    objComplex.circular = objComplex
    objComplex[Symbol()] = ‘symbol’

    function deepClone(objComplex, mapx = new Map()) {

    if (typeof objComplex !== ‘object’) {
    return objComplex
    }

    const objClone = Array.isArray(objComplex) ? [] : {}
    if (mapx.get(objComplex)) {
    return mapx.get(objComplex)
    }
    mapx.set(objComplex, objClone)
    // for(let key in objComplex) {
    // objClone[key] = deepClone(objComplex[key], mapx)
    // }
    Reflect.ownKeys(Array.isArray(objComplex) ? […objComplex] : {…objComplex}).forEach(key => {
    // Reflect.ownKeys(obj)返回对象参数的所有属性,包含 symbol 类型的属性
    objClone[key] = deepClone(objComplex[key], mapx)
    })
    return objClone
    }
    const res = deepClone(objComplex)
    console.log(res, ‘res’)
    `

  • 2021/06/20 优化
  • 下面的 ownKeys 参数中是不须要判断是不是数组的,因为 ownKeys 能够遍历数组和对象

    <script>
        // deep clone
        const obj = {
          name: "woow_wu7",
          address: {
            city: "chongqing",
            districe: "yubei",
            town: "jiazhou",
            detail: ["chongqign", "yubei", "jiazhou"],
          },
          arr: [1, 2],
          [Symbol("unique")]: "unique",
        };
        obj.circle = obj;
    
        const deepClone = (param, map = new Map()) => {let typeParams = Object.prototype.toString.call(param);
    
          if (typeof param !== "object" && typeof param !== "function") {return param;}
    
          if (map.get(param)) {return map.get(param);
          }
    
          let resObj = Array.isArray(param) ? [] : {};
    
          map.set(param, resObj);
    
          // for (let key in param) {//   resObj[key] = deepClone(param[key], map);
          // }
          Reflect.ownKeys(param).forEach((key) => { // ownKeys 参数中,不必做判断是不是数组了
            resObj[key] = deepClone(param[key], map);
          });
    
          return resObj;
        };
    
        const newObj = deepClone(obj);
        newObj.name = "222";
        console.log(`newObj`, newObj);
        console.log(`obj`, obj);
      </script>
  • 结构化克隆算法解决其余对象的拷贝 (4)

    • <font color=red> 要求: 能够拷贝对象和数组,并解决循环援用问题(Map 缓存),并解决 Symbol 数据类型(Reflect.ownKeys()),解决其余对象的拷贝(结构化克隆),构造函数生成实例的原型对象的拷贝 </font>
    • 比方:Date,Regexp,构造函数生成的实例的原型对象的属性拷贝
    一句话总结:
    (1)赋值不会开翻新的堆内存空间,而浅拷贝会开翻新的堆内存空间;
    (2)赋值:扭转对象属性相互影响;
    (3)浅拷贝:扭转属性值是原始类型时,互不烦扰。扭转的属性值是援用类型时,相互影响

  • </table></tr></td>
  • 赋值和浅拷贝的区别实例

    赋值和浅拷贝的区别
    
    var a = {
      name: 'woow_wu',
      score: {
        ch: 90,
        en: 80
      }
    };
    var b = a
    var c = {...a}
    console.log(a===b, '赋值 => 不会开翻新的堆空间,批改相互影响') // true,阐明是同一份堆数据
    console.log(a===c, '浅拷贝 => 会开翻新的堆空间,批改原始值属性互不烦扰,批改援用值属性,相互影响') // false,不同堆数据
    a.name = 'wang'
    console.log(b, 'b') // 相互影响
    console.log(c, 'c => 浅拷贝,批改属性值为根本类型 => 互不烦扰') // 互不烦扰
    a.score.en = 100
    console.log(c, 'c => 浅拷贝,批改属性值为援用类型 => 相互影响') // 相互影响

    浅拷贝

    对象的浅拷贝

    • Object.assign()
    • {…} 开展运算符

    数组浅拷贝

    • Array.prototype.slice() // 不传参
    • Array.prototype.concat() // 不传参
    • […] 开展运算符

      const arr = [1, 2, 3]
      ---
    • slice
    • slice(start, end)

      • 截取指标数组的一部分,———————————– (返回一个新数组,不扭转原数组)
      • start 起始地位,从 0 开始,能够取到
      • end 终止地位,留神取不到 end // arr.slice(0, 2) // [1, 2]
    • 上面三种写法等价

      • arr.slice()
      • arr.slice(0)
      • arr.slice(0, 3) 三者的后果一样
    • concat
    • concat

      • 用于多个数组的合并,它将新数组的成员,增加在原属数组的尾部,—- (返回一个新数组,不扭转原数组)
      • 参数

        • concat 的参数除了是 (数组) 还能够是 (其余任意类型的值)
    • 数组的浅拷贝
    • arr.concat() // 不加参数
    • arr.slice() // 不加参数
    • […arr]

    深拷贝

    办法一 JSON.parse(JSON.stringify())

    • 毛病:
    • 只能深拷贝对象和数组,但不能拷贝函数,循环援用,原型链上的属性和办法(Date, RegExp, Error 等)

      const objComplex = {
      name: 'woow_wu7',
      address: {
        city: 'chongqing',
        district: 'yubei',
        town: 'jiazhou',
        detail: ['chongqing', 'yubei', 'jiazhou']
      },
      arr: [1,2, {l:20, r: 30}],
      fn: function(){}, // Function
      date: new Date(), // Date
      err: new Error(), // Error
      reg: new RegExp(), // RegExp
      number: 1,
      string: '',
      boolean: true,
      null: null,
      undefined: undefined,
      symbol: Symbol('symbol'), // Symbol
      }
      const copy = JSON.parse(JSON.stringify(objComplex))
      console.log(objComplex, 'objComplex')
      console.log(copy, 'copy')
      
      如下图:JSON.parse(JSON.stringify()) 不能拷贝 function,Date,Error,RegExp,等对象

    办法二

    根底版 – for…in 循环递归(1)

    • <font color=red> 要求:能够拷贝对象和数组 </font>
    • 未解决:

      • 循环援用
      • Symbol()类型 key 的属性对应值的拷贝
      • 其余对象的复制如 Date,Error,Regexp,Symbol 数据类型等

        const objComplex = {
        name: 'woow_wu7',
        address: {
        city: 'chongqing',
        district: 'yubei',
        town: 'jiazhou',
        detail: ['chongqing', 'yubei', 'jiazhou']
        },
        score: [100, 200]
        }
        
        function deepClone(parameter) {const parameterType = Object.prototype.toString.call(parameter).slice(8, -1)
        // 获取类型字符串
        // Array.prototype.slice(8, -1) 从下标为 8 的字符开始截取,直到倒数第 2 个值
        // 因为第一个参数地位能够取到,第二个参数地位取不到
        const cloneObj = null
        // 参数是数组,赋值[]
        // 参数是对象,赋值{}
        // 其余类型:间接返回
        if (parameterType === 'Array') {cloneObj = []
        }
        else if (parameterType === 'Object') {cloneObj = {}
        }
        else {return parameter}
        
        for(let key in parameter) {
        // for...in 
        // 1. 循环用来遍历对象 (所有可遍历的属性),会 (跳过不可遍历的属性)
        // 2. 不仅能够遍历 (本身属性),还能够遍历 (继承的属性)
        // 3. 所以个别状况下,(for...in 都要联合 hasOwnProperty 来遍历本身的属性)
        
        if (parameter.hasOwnProperty(key)) {
          // 是否是本身属性
          if (typeof parameter[key] === 'object') {
            // 对象或数组,持续判断
            // 这里应用 typeof 没有去区是分数组或对象,因为会在 deepClone 中去做判断
            cloneObj[key] = deepClone(parameter[key])
          } else {
            // typeof 不是 objet
            // 则有可能是:number string boolean undefined symbol function
            // 这里没有思考 function 的拷贝
            cloneObj[key] = parameter[key]
          }
        }
        }
        
        return cloneObj
        }
        const res = deepClone(objComplex)
        console.log(res, 'res')
    ----------
    更精简的写法
    
    const obj = {
      name: 'woow_wu7',
      address: {
        city: 'chongqing',
        districe: 'yubei',
        town: 'jiazhou',
        detail: ['chongqign', 'yubei', 'jiazhou']
      },
      arr: [1,2]
    }
    
    function deepClone(parameter) {if (typeof parameter === 'object') {
        // 这里只思考 对象和数组
        // typeof 返回值是字符串,有 7 种
        // number string boolean undefined symbol function object
        const objClone = Array.isArray(parameter) ? [] : {}
        for (let key in parameter) {if (parameter.hasOwnProperty(key)) {objClone[key] = deepClone(parameter[key])
            // 不论是对象类型还是根本数据类型,都去调用 deepClone(parameter[key])
            // 在 deepClone()函数中会去判断对象类型是数组还是对象,根本数据类型间接返回并赋值给 objClone[key]
          }
        }
        return objClone
      }
      else {
        // 不是数组和对象间接返回形参
        // 留神形参是新申明的变量
        return parameter
      }
    }
    
    const res = deepClone(obj)
    console.log(obj)
    console.log(res)
    

    Map 解决循环援用 – for…in 循环递归(2)

    • <font color=red> 要求: 能够拷贝对象和数组,并解决循环援用问题 </font>

      (1) 什么是循环援用?const obj = {name: 'wang'}
      obj.circle = obj
      // obj 新增 circle 属性,值是 obj 对象自身
      // 这样的状况,像下面的代码例子中,for..in 循环中 deepClone(parameter[key])会一直反复执行
      // 最终造成内存溢出
      
      
      ----------
    • 查看 map 实例中是否有克隆过的对象
    • 如果存在,间接返回
    • 如果不存在,就赋值键值对,key 是传入的对象,value 是克隆的对象

      var objComplex = {
      address: {
      city: ‘chongqing’,
      town: ‘jiazhou’,
      },
      score: [100, 200],
      }
      objComplex.circular = objComplex

      function deepClone(objComplex, mapx = new Map()) {// 默认值,是一个空的 map 实例

      if (typeof objComplex !== ‘object’) {
      // 不是对象和数组间接返回
      return objComplex
      }
      const objClone = Array.isArray(objComplex) ? [] : {}

      if (mapx.get(objComplex)) {
      // 存在被克隆的对象,间接返回
      return mapx.get(objComplex)
      }
      // 不存在,就增加键值对,将被克隆对象作为 key,克隆的对象作为 value
      mapx.set(objComplex, objClone)

      for(let key in objComplex) {
      objClone[key] = deepClone(objComplex[key], mapx)
      // 留神:mapx 要传入做判断
      // 不论 objComplex[key] 是什么类型,都调用 deepClone(),因为在 deepClone()中会判断
      }
      return objClone
      }
      const res = deepClone(objComplex) // 这样就不会内存溢出了
      console.log(res, ‘res’)

    Reflect 解决 Symbol 数据类型复制 – Reflect.ownKeys()循环递归(3)

    • <font color=red> 要求: 能够拷贝对象和数组,并解决循环援用问题,并解决 Symbol 数据类型 </font>
    • 解决 Symbol 数据类型
    • Symbol 不能用 new 去调用,参数能够是数组
    • Reflect.ownKeys(obj)返回参数对象的所有本身属性,包含 symbol 数据类型的属性

      • 参数如果不是 obj,则会抛出 typeError
      • 毛病:Reflect 不能取到原型链上的属性和办法
    毛病:不能解决 Error,不能解决 Function,不能解决 DOM 节点

    `
    function Message() {
    this.sex = ‘man’
    }
    Message.prototype.age = 1000

    var objComplex = {
    address: {
    city: ‘chongqing’,
    town: ‘jiazhou’,
    },
    score: [100, 200],
    [Symbol()]: ‘symbol’,
    date: new Date(),
    reg: new RegExp(),
    fn: function () {},
    err: new Error(),
    message: new Message()
    }
    objComplex.circle = objComplex

    function deepClone(objComplex, mapx = new Map()) {

    if (typeof objComplex !== ‘object’) {
    return objComplex
    }

    let objClone = Array.isArray(objComplex) ? [] : {}
    if (mapx.get(objComplex)) {
    return mapx.get(objComplex)
    }
    mapx.set(objComplex, objClone)

    // for(let key in objComplex) {
    // objClone[key] = deepClone(objComplex[key], mapx)
    // }

    // Reflect.ownKeys(Array.isArray(parameter) ? […parameter] : {…parameter}).forEach(key => {
    // objClone[key] = deepClone(parameter[key], mapx)
    // })

    switch (objComplex.constructor) {// 传入的参数对象的构造函数
    case Date:
    case RegExp:
    case Message: // 自定义的构造函数
    objClone = new objComplex.constructor(objComplex)
    break
    // 如果是 Date,RegExp,Message 构造函数的申请
    // 就别离用这些构造函数生成实例,而后再赋值给拷贝对象
    default:
    Reflect.ownKeys(Array.isArray(objComplex) ? […objComplex] : {…objComplex}).forEach(key => {
    objClone[key] = deepClone(objComplex[key], mapx)
    })
    }
    return objClone
    }
    const res = deepClone(objComplex)
    console.log(res, ‘res’)
    console.log(res.message.age, ‘ 克隆的对象 ’)
    console.log(objComplex.message.age, ‘ 原对象 ’)
    `

2021/07/17 温习

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <script>
      // deepClone
      // 1. Map 解决循环援用 => 缓存
      // 2. Reflect 解决 Symbol()数据类型 => Reflect.ownKeys()
      // 3. 结构化克隆解决非凡对象的拷贝 => Date RegExp
      //  - 尽管结构化克隆解决了 (Date) (RegExp) 对象的拷贝问题
      //  - 然而结构化克隆依然没有解决 (Error) (function) (DOM 节点) 的拷贝问题

      const obj = {
        num: 1,
        str: "str",
        boo: true,
        und: undefined,
        [Symbol()]: Symbol(),
        arr: [1, 2, 3],
        obj: {name: "woow_wu7"},
        date: new Date(),
        regexp: new RegExp(),};
      obj.circle = obj;

      const deepClone = (params, map = new Map()) => {if (typeof params !== "object") {return params;}
        let resObj = Array.isArray(params) ? [] : {};

        if (map.get(params)) {return map.get(params);
        }

        map.set(params, resObj);

        // for (let key in params) {//   if (params.hasOwnProperty(key)) {//     resObj[key] = deepClone(params[key], map);
        //   }
        // }

        // Reflect.ownKeys(params).forEach(key => {//   resObj[key] = deepClone(params[key], map)
        // })

        switch (params.constructor) {
          case Date:
          case RegExp:
            resObj = new params.constructor(params);
            break;
          default:
            Reflect.ownKeys(params).forEach((key) => {resObj[key] = deepClone(params[key], map);
            });
            break;
        }

        return resObj;
      };

      const res = deepClone(obj);
      console.log(`res`, res);
      console.log(`obj`, obj);
    </script>
  </body>
</html>

根本:https://juejin.im/post/684490…
深刻:https://juejin.im/post/684490…
知乎(lodash deepClone 源码剖析):https://zhuanlan.zhihu.com/p/…
stack,heap:https://segmentfault.com/a/11…
https://juejin.im/post/684490…
我的简书 https://www.jianshu.com/p/a23…

正文完
 0