问题代码
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)
按道理来说这里的option里面的内容应该都已经被深拷贝了
但是我们来看打印结果
深拷贝失效了
在这里我们可以看到,事实上我们只改了series第一个数组里面 priceList里面的值,但是下面series[1].priceList[0]的值也发生了改变变成了5
显然lodash的深拷贝失效了
优先解决问题
因为这是业务当中实际遇到的问题,所以我必须优先把问题解决
第一种方案-暴力解决
使用 JSON.parse(JSON.stringify(data)) 就可以解决这个问题 但是使用这个的话,会存在var arr = [{name:'123',hd:undefined}] 数据转化后 undefined属性丢失的问题 不太稳妥
第二种方案-探索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
}
直接进行深度递归赋值拷贝即可-这样即可解决重复引用的问题
基于实际业务的思考
虽然解决后的代码,没有能够解决对象循环引用的问题,但是注意一点。 我们做事情要基于实际业务。
比如虽然我们知道,循环引用的问题,但是你真的在实际业务当中有遇到过循环引用吗。
a.item = a 显然我还没有遇到过有人这么写代码产生循环引用
因此遇到这样的问题,我立马放弃了lodash的cloneDeep作为深拷贝工具 独立封装一个深拷贝函数供自己使用。
一切都要基于实际业务出发,而非为了技术而技术。