深浅拷贝与实现
浅拷贝只复制一层:对象属性值是引用类型时仍与原对象共享同一份。原生浅拷贝是 Object.assign({}, obj) 或展开 {...obj}。深拷贝递归复制所有层级,最实用的答案是 structuredClone(obj)(现代浏览器内置,支持循环引用,不拷贝函数);旧方案 JSON.parse(JSON.stringify(obj)) 不支持函数、undefined、循环引用。
面试真正考的是手写深拷贝:递归 + WeakMap 记录已拷贝对象(解决循环引用)+ 特殊对象处理(数组、Date、RegExp、Map/Set)。用 WeakMap 而非 Map:键是弱引用,拷贝完成后可被垃圾回收,不长期占用内存。
- 浅拷贝:Object.assign / 展开运算符,只复制一层
- JSON 序列化法不支持函数 / undefined / 循环引用,structuredClone 是现代答案
- 手写要点:递归 + WeakMap 破循环引用 + Date/RegExp/Map/Set 特判
JS
// 浅拷贝 const a = { x: 1, sub: { y: 2 } }; const b = { ...a }; b.sub.y = 99; console.log('浅拷贝共享引用:', a.sub.y === 99); // true —— 原对象被改了 // 深拷贝:现代一行版 const c = structuredClone(a); c.sub.y = 0; console.log('structuredClone 后原对象:', a.sub.y); // 2 —— 互不影响 // 手写深拷贝(面试标答:递归 + WeakMap + 特殊类型) function deepClone(obj, hash = new WeakMap()) { if (obj === null || typeof obj !== 'object') return obj; // 原始值直接返回 if (hash.has(obj)) return hash.get(obj); // 循环引用:返回已拷贝副本 // 特殊对象 if (obj instanceof Date) return new Date(obj); if (obj instanceof RegExp) return new RegExp(obj.source, obj.flags); if (obj instanceof Map) { const m = new Map(); hash.set(obj, m); obj.forEach((v, k) => m.set(deepClone(k, hash), deepClone(v, hash))); return m; } if (obj instanceof Set) { const s = new Set(); hash.set(obj, s); obj.forEach(v => s.add(deepClone(v, hash))); return s; } // 普通对象 / 数组 const clone = Array.isArray(obj) ? [] : {}; hash.set(obj, clone); Object.keys(obj).forEach(k => { clone[k] = deepClone(obj[k], hash); }); return clone; } // 测试循环引用 const o = { n: 1 }; o.self = o; const o2 = deepClone(o); console.log('循环引用通过:', o2.self === o2); // true,且没有爆栈
本节要点深拷贝三要素:递归复制、WeakMap 破循环引用、Date/RegExp/Map/Set 特殊处理;实际项目用 structuredClone。




