JavaScript 拷贝的几种方式

20 阅读1分钟

我们平时开发中处理前后端数据时会有拷贝数据的情况,今天我们学习下在 JavaScript 中实现拷贝的几种方式。

JSON.parse(JSON.stringify(obj))

const obj = {
    a: 1,
    b: 'string',
    c: true,
    d: NaN,
    e: Infinity,
    f: undefined,
    g: null,
    h: Symbol('symbol'),
    i: new Date('2024-02-05'),
    j: new RegExp(/^1/g),
    k: {
        age: 21,
    },
    l: function () {
        console.log('function');
    },
};

const cloneObj = JSON.parse(JSON.stringify(obj));
console.log(cloneObj);

截屏2024-02-06 10.29.01.png

拷贝结果如图,通过上图我们知道这种拷贝的缺点是:

  1. 会忽略值为 undefined 的属性
  2. 时间对象的会被转为字符串
  3. 正则表达式会被转为空对象 {}
  4. NaN 和 Infinity 会被转为 null
  5. 无法处理循环引用

Object.assign({}, obj)

const cloneObj = Object.assign({}, obj);
console.log(cloneObj);

截屏2024-02-06 10.35.51.png

Object.assign 拷贝属性不会丢失,但是如果属性是引用类型拷贝之后还是会指向同一个引用

实现一个 deepClone 函数

function deepClone(obj, weakMap = new WeakMap()) {
    if (obj === null || typeof obj !== 'object') {
        return obj;
    }

    if (obj instanceof RegExp) {
        return new RegExp(obj);
    }

    if (obj instanceof Date) {
        return new Date(obj);
    }

    if (weakMap.has(obj)) {
        return weakMap.get(obj);
    }

    const clone = Array.isArray(obj) ? [] : {};
    for (let key in obj) {
        clone[key] = deepClone(obj[key], weakMap);
    }

    return clone;
}