深拷贝需重建特殊内置对象实例而非复制属性:用Object.prototype.toString.call()精准识别Date、RegExp、Map、Set类型;Date用getTime()重建,RegExp用source和flags重建,Map/Set需逐项深拷贝键值并处理循环引用。

深拷贝中识别并保留特殊内置对象的类型和结构,关键不是“复制属性”,而是“重建实例”——用对应构造函数创建新对象,并注入原始数据。
用 Object.prototype.toString.call() 精准识别类型
不能依赖 typeof,因为 Date、RegExp、Map、Set 全部返回 "object"。必须用:
-
Date →
Object.prototype.toString.call(obj) === "[object Date]"或obj instanceof Date -
RegExp →
Object.prototype.toString.call(obj) === "[object RegExp]"或obj instanceof RegExp -
Map →
Object.prototype.toString.call(obj) === "[object Map]"或obj instanceof Map -
Set →
Object.prototype.toString.call(obj) === "[object Set]"或obj instanceof Set
判断后立即分支处理,避免进入通用对象递归逻辑。
Date 和 RegExp:用构造函数重建,传入原始状态
它们内部有不可枚举的状态(时间戳、正则源码与标志),不能遍历属性复制。
-
Date:取
obj.getTime(),再new Date(time);避免new Date(obj),防止字符串输入误解析 -
RegExp:取
obj.source和obj.flags,再new RegExp(source, flags)
Map 和 Set:新建实例 + 逐项深拷贝键值
它们的键和值都可能是引用类型(比如 Map 的 key 是对象,value 是数组),所以不能只展开或浅拷贝。
-
Map:
const cloned = new Map(),然后遍历obj.entries(),对每一对[key, value]都调用深拷贝函数 -
Set:
const cloned = new Set(),遍历obj.values(),每个元素都深拷贝后add() - 注意:Map 的 key 若为对象,也要走循环引用检测(WeakMap 缓存)
保持原型链与不可枚举属性(可选但推荐)
普通对象默认用 Object.create(Object.getPrototypeOf(obj)) 创建,能继承原型方法;而 Date/RegExp/Map/Set 已由构造函数保证原型正确,无需额外处理。若需保留不可枚举属性(如某些库添加的私有字段),要用 Object.getOwnPropertyNames() 和 Object.getOwnPropertySymbols() 补充遍历。

















