02 对象拷贝

66 阅读1分钟

数组拷贝

javascript 原生提供了一些可以实现数组项为原始数据类型的数组的拷贝方法: (但是这些方法对于数组项为引用类型的数组则不再有效) Array.prototype.sliceArray.prototype.concatArray.from

const arr = [1, 3, 1, 4, 'love', 'you'];
const temp = arr.concat();
const temp1 = arr.slice();
const temp2 = Array.from(arr)

利用对象序列化拷贝对象

一般情况下可以通过 JSON.parse + JSON.stringify 对对象进行拷贝:

const obj = {
    boy: 'Jack',
    body: {
        weight: 80,
        height: 185
    }
};
const copiedObj = JSON.parse(JSON.stringify(obj));

但是这种方法具有很大的局限性:

  • 对象的属性中包含函数、正则、日期对象
  • 对象中存在循环引用
/* 属性包含函数、正则、日期对象 */
const obj = {
    fn(){ return null },
    reg: /sw+/i,
    date: new Date()
}

/*
copiedObj = {
    date: "2022-09-08T12:52:10.304Z" // 日期对象序列化调用其 toJSON() 方法
    reg: {} // reg 对象序列化将被转化为 {}
}
// 函数将被序列化为 undefined
*/
const copiedObj = JSON.parse(JSON.stringify(obj))

/* 存在循环引用的对象 */
const body = {
    weight: 80,
    height: 185
}
const person = {
    name: 'Jack'
};
person.body = body
body.self = person

// 抛出异常: Uncaught TypeError: Converting circular structure to JSON
const copiedPerson = JSON.parse(JSON.stringify(person));

通用深拷贝方法

深度遍历:

const deepCopy = (function () {
    function getType(raw) {
        return Object.prototype.toString.call(raw).slice(8, -1).toLowerCase();
    }

    const map = new WeakMap();

    return function copy(obj) {
        const type = getType(obj);
        if (type === "null") return obj;
        if (type === "undefined") return obj;
        if (type === "function") return obj; // 函数
        if (type === "regexp") return obj; // 正则
        if (type === "date") return new Date(obj.getTime()); // 日期

        if (type === "array") {
            if (map.get(obj)) return obj;
            map.set(obj, true);
            return obj.map((v) => copy(v));
        }

        if (type === "object") {
            if (map.get(obj)) return obj;
            map.set(obj, true);
            const temp = {};
            Object.keys(obj).forEach((k) => {
                temp[k] = copy(obj[k]);
            });
            return temp;
        }
        return obj;
    };
})();