关于ladsh深拷贝的问题:cloneDeep()

发布时间 2023-10-17 22:12:57作者: zhaoLei_Free

内容来源:99%的前端都不知道的lodash深拷贝的'BUG' - 掘金 (juejin.cn)

问题代码

import { cloneDeep } from 'lodash' 
const priceList = [1, 2] 
const animals = { priceList } 
const option = { series: ['dog', 'cat'].map(item => animals) } 
const o = cloneDeep(option) 
o.series[0].priceList[0] = 5
console.log('o: ', o) 

打印结果

 

深拷贝失效了

在这里我们可以看到,事实上我们只改了series第一个数组里面 priceList里面的值,但是下面series[1].priceList[0]的值也发生了改变变成了5

显然lodash的深拷贝失效了

 

 

探索loadsh源码

因为内部源码太长,我将核心内容用伪代码的形式展现

const deepCopy = (data, map = new WeakMap()) => {
  if (typeof data !== 'object') {
    return data
  }
  if (map.get(data)) {
    return map.get(data)
  }
  const copy = new data.constructor()
  map.set(data, copy)
  for (let key in data) {
    if (data.hasOwnProperty(key)) {
      copy[key] = deepCopy(data[key], map)
    }
  }
  return copy
}

这段代码细看通过 map.get,map.set 解决了对象循环引用的问题 但是却存在一个巨大隐患,对于这种const priceList = [1, 2] 。map.get会被认定为是同一个 直接return出去 返回了相同的引用地址 导致深拷贝失效

如何解决这个问题

const deepCopy = (data) => {
  if (typeof data !== 'object') {
    return data
  }
  const copy = new data.constructor()
  for (let key in data) {
    if (data.hasOwnProperty(key)) {
      copy[key] = deepCopy(data[key])
    }
  }
  return copy
}

 

直接进行深度递归赋值拷贝即可-这样即可解决重复引用的问题

个人理解:

  我认为应该不是从priceList数组开始出现的引用问题,而是从animals这里出的问题。series[animals,animals]。animals是相同的,所以出现了这个问题。