js手写深拷贝

1,055 阅读1分钟

js手写深拷贝

思路

  • 主要思路就是利用遍历和递归去实现。
  1. typeof 判断不是对象的直接返回。
  2. instanceof 判断是 Date、RegExp 的 new 一个对应实例对象返回。
  3. 如果是【数组】或【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)