「这是我参与2022首次更文挑战的第4天,活动详情查看:2022首次更文挑战」。
首先如果你弄不清楚什么是深浅拷贝,你需要先弄清楚。下面我们实现一个简单的浅拷贝。
浅拷贝手写实现,我们需要判断赋值对象的类型,如果是基础类型就直接返回,引用类型的话,null直接返回null,再判断是数组还是对象,然后for in循环去赋值。
一、浅拷贝的实现
function clone(target) {
if (target === null) { // null也是对象类型
return target
}
if (typeof target === 'object') {
let cloneTarget = Array.isArray(target) ? [] : {}
for (const key in target) {
if (Object.hasOwnProperty.call(target, key)) {
cloneTarget[key] = target[key]
}
}
return cloneTarget
}
return target
}
二、深拷贝的实现
对于深拷贝,我们知道对于对象里面属性还是对象,这样可能一直嵌套下去,所以我们需要用到递归,对于上面的函数,我们只需要修改一点(顺便我们将方法名改为deepClone)。
cloneTarget[key] = deepClone(target[key])
如果你在面试中实现了上面的方法,面试官可能会问你循环引用怎么解决呢? 好,我们先弄清楚什么是循环引用,我们先看一个例子:
const target = {
a: {
b: 111
}
}
target.t = target
deepClone(target)
我们会发现这时候,报错了,死循环了,你可以再deepClone中打印target看看;这样我们就清楚了,一个对象的属性调用自己就出现了循环引用的情况。
我们怎么解决呢?就是需要找一个地方,把拷贝过的存储起来,在循环赋值的时候,我们先去判断,是不是已经拷贝过,如果是,就直接返回这个存储的对象即可,我们这里采用WeakMap。
function deepClone(target, weakMap = new WeakMap()) {
if (target === null) { // null也是对象类型
return target
}
if (typeof target === 'object') {
let cloneTarget = Array.isArray(target) ? [] : {}
if (weakMap.has(target)) {
return weakMap.get(target)
}
weakMap.set(target, cloneTarget)
for (const key in target) {
if (Object.hasOwnProperty.call(target, key)) {
cloneTarget[key] = deepClone(target[key], weakMap)
}
}
return cloneTarget
}
return target
}
当你这样写,面试官一定会问你WeakMap,所以你一定得弄清楚WeakMap。
下面我们看一个例子:
const target = {
a: {
b: 111,
s: Symbol(),
[Symbol()]: 'symbol1',
date: new Date('2022-12-12'),
reg: new RegExp('abc')
}
}
target.t = target
target1 = deepClone(target)
target.t.a.b = 999
target.t.a.date = new Date('2021-12-1')
console.log(111, target, target1)
我们可以看到对于
symbol类型的key,for in循环是不行的,我们采用Reflect.ownKeys去解决。
对于
RegExp、Date等类型的处理,大家可以看看这篇文章juejin.cn/post/684490…