js手写深拷贝
思路
- 主要思路就是利用遍历和递归去实现。
- typeof 判断不是对象的直接返回。
- instanceof 判断是 Date、RegExp 的 new 一个对应实例对象返回。
- 如果是【数组】或【json对象】就进行遍历和递归遍历。
浅拷贝
function clone(obj) {
if (typeof obj !== 'object' || obj == null) return obj
const res = obj instanceof Array ? [] : {}
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
res[key] = obj[key]
}
}
return res
}
测试示例:
const o1 = {
a: 1,
b: 2,
c: 3,
d: {
dd: 100
}
}
const o2 = clone(o1)
console.log(o1 === o2) // false
console.log(o1.d === o2.d) // true
简单版深拷贝
function deepClone(obj) {
if (typeof obj !== 'object' || obj == null) return obj
let res = obj instanceof Array ? [] : {}
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
res[key] = deepClone(obj[key])
}
}
return res
}
测试示例:
const o1 = {
a: 1,
b: 2,
c: 3,
d: {
dd: 100
}
}
const o2 = deepClone(o1)
console.log(o1 === o2) // false
console.log(o1.d === o2.d) // false
// 循环引用举例
const o3 = {
a: 1
}
o3.b = o3
console.log(o3) // 不会报错
const o4 = deepClone(o3) // Uncaught RangeError: Maximum call stack size exceeded
console.log(o4)
进阶版深拷贝
基于简单版,还考虑了内置对象比如 Date、RegExp,以及解决了循环引用的问题。
function deepClone(obj, map = new WeakMap()) {
if (map.get(obj)) return obj
if (typeof obj !== 'object' || obj == null) return obj
if (obj instanceof Date) return new Date(obj)
if (obj instanceof RegExp) return new RegExp(obj)
let res = new obj.constructor()
map.set(obj, true)
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
res[key] = deepClone(obj[key], map)
}
}
return res
}
测试示例:
// 循环引用
const o1 = {
a: 1
}
o1.b = o1
const o2 = deepClone(o1)
console.log(o2)