JS實現深拷貝(解決循環引用等問題)


基本思路是遞歸,主要是需要針對不同的數據類型(null, 數組,Date,正則表達式 等)進行精細的處理,並且用WeakMap解決循環引用,避免陷入死循環。

函數的深拷貝暫時沒有思路,用 new Function(fn.toString()) 會有些問題,所以直接拷貝引用了,請大家賜教。

 

/**
 * 深拷貝
 */

const wm = new WeakMap();

function deepClone(target) {
    let result;
    if (typeof target === 'object') {
        // null
        if (target === null) {
            result = target;
        }
        // Array
        else if (Array.isArray(target)) {
            result = [];
            target.forEach(item => result.push(deepClone(item)));
        }
        // Date
        else if (target instanceof Date) {
            result = new Date(target);
        }
        // regular expression
        else if (target instanceof RegExp) {
            result = new RegExp(target);
        }
        // plain object
        else {
            // detect circular reference
            // 用WeakMap的key保存原對象的引用記錄, value是對應的深拷貝對象的引用
            // 例如: a:{b:{c:{d: null}}}, d=a, a 的深拷貝對象是 copy, 則 weakmap 里保存一條 a->copy 記錄
            //     當遞歸拷貝到d, 發現d指向a,而a已經存在於weakmap,則讓新d指向copy
            if (wm.has(target)) {
                result = wm.get(target);
            }
            else {
                result = {};
                wm.set(target, result);
                for (let prop in target) {
                    result[prop] = deepClone(target[prop]);
                }
            }
        }
    }
    // function, primary type
    else {
        result = target;
    }
    return result;
}

(function () {
    const a = {
        num: 123,
        say() {
            return 'Hello';
        },
        arr: [1, 2, [4, {name: 'Jack'}]],
        n: null,
        un: undefined,
        d: new Date(),
        reg: /[a-z0-9]+/,
        b: {
            c: {
                d: null
            }
        }
    };
    a.b.c.d = a;
    const copy = deepClone(a);
    console.log(copy)
    console.log(copy === a) // false
    console.log(copy.say()); // Hello
    console.log(copy.arr);
    console.log(copy.arr[2][1] === a.arr[2][1]); // false
    console.log(copy.b.c.d === copy) // true,循環引用得到復制
})();


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM