深拷贝函数的实现

使用JSON.parse(Json.stringify())实现深拷贝有哪些坑?

  • 如果属性值是undefined、或者函数,序列化后属性丢失;
  • 如果属性值是RegExp、Error对象,序列化后值是{};
  • 如果属性值是NaN、Infinity和-Infinity,则序列化的结果会变成null

因此一般都采用自定义函数实现:

function deepClone(obj, map = new WeakMap()) {
    // 不是对象,直接返回(包括基础数据类型、 `null` 和 `undefined`)
    if (obj === null || obj === undefined || typeof obj !== "object") return obj;
    // 避免循环引用
    if (map.has(obj)) return map.get(obj);
    // 处理特殊对象(Date / RegExp)
    if (obj instanceof Date) return new Date(obj);
    if (obj instanceof RegExp) return new RegExp(obj);
    //创建新对象或数组
    const cloneObj = Array.isArray(obj) ? [] : {};
    // 存入 `WeakMap`,防止循环引用
    map.set(obj, cloneObj);
    //获取所有键,包括 `Symbol`
    const keys = Reflect.ownKeys(obj); 
    //递归拷贝属性
    keys.forEach((key) => {
        cloneObj[key] = deepClone(obj[key], map);
    });
    return cloneObj;
}

//测试用例
const obj1 = {
    num: 1,
    str: "hello",
    arr: [1, 2, { a: 3 }],
    obj: { x: 10 },
    date: new Date(),
    regex: /abc/g,
    sym: Symbol("sym"),
};
obj1.self = obj1; // 🌀 创建循环引用

const clone = deepClone(obj1);
console.log(clone);
console.log(clone === obj1); // false 证明是深拷贝
console.log(clone.arr === obj1.arr); // false 证明数组被深拷贝
console.log(clone.obj === obj1.obj); // false 证明对象被深拷贝
console.log(clone.date === obj1.date); // false 证明 Date 被拷贝
console.log(clone.regex === obj1.regex); // false 证明 RegExp 被拷贝
console.log(clone.self === clone); // true 证明循环引用正确处理

 

posted @ 2024-11-11 11:48  我是格鲁特  阅读(41)  评论(0)    收藏  举报