基本思路是遞歸,主要是需要針對不同的數據類型(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,循環引用得到復制 })();
