lodash的clonedeep默认不拷贝原型链属性,仅深拷贝对象自身的可枚举属性,以保障数据纯净性与安全性;它通过object.keys()和hasownproperty确保跳过原型属性,避免静态方法污染、instanceof失真及getter/setter副作用。

lodash 的 cloneDeep 默认不拷贝原型链上的属性,这是它保障数据纯净性和安全性的关键设计。它只深拷贝对象自身的可枚举属性(own enumerable properties),对原型上的方法、访问器或继承来的字段一律忽略。
为什么默认不拷贝原型
JavaScript 中原型链是共享的,拷贝原型会带来不可控风险:比如意外复制了类的静态方法、污染新对象的 instanceof 判断、或引发不可预知的 getter/setter 副作用。lodash 选择“只拷贝数据,不拷贝行为”,符合大多数业务场景下对纯数据副本的需求。
如何识别并跳过原型属性
lodash 内部使用 Object.keys() 或等效机制遍历属性,该方法天然只返回对象自身可枚举属性,不包含原型链上的任何键。同时配合 hasOwnProperty 做二次校验,确保每个被复制的 key 确实属于当前对象实例。
想拷贝原型?需主动开启
若确有需要(如测试场景模拟完整实例),可通过 cloneDeepWith 配合自定义 customizer 实现,但需自行处理以下细节:
- 用 Object.getOwnPropertyNames() + Object.getOwnPropertySymbols() 获取全部自有属性(含不可枚举)
- 用 Object.getPrototypeOf() 向上遍历原型链,逐层提取属性描述符
- 对每个属性调用 Object.getOwnPropertyDescriptor(),判断是否为数据属性或存取器,并安全重建
- 注意避免循环引用——原型链本身可能形成闭环(如 Object.prototype.__proto__ === null)
与原生 structuredClone 的对比
现代浏览器支持的 structuredClone() 同样不拷贝原型,且明确规范“仅序列化可传输值”。lodash 的行为与此一致,但更早提供跨环境兼容性。两者都把“原型”视为语义边界,而非数据一部分。











