深拷贝默认不保留原型链,因json.parse(json.stringify())、structuredclone等仅复制自有属性和嵌套数据,不复制构造函数、方法、symbol键及[[prototype]]内部状态。

JavaScript 中深拷贝默认不保留原型链,因为标准方法(如 JSON.parse(JSON.stringify())、结构化克隆或 Lodash 的 cloneDeep)只复制自有属性和嵌套数据,不复制构造函数、方法、访问器、Symbol 键,更不会重建原型关系。
深拷贝为何丢失原型结构
原型信息属于对象的内部状态([[Prototype]]),不是可枚举属性,也不在序列化范围中。例如:
class Person {
constructor(name) { this.name = name; }
greet() { return `Hi, ${this.name}`; }
}
const p = new Person('Alice');
console.log(p instanceof Person); // true
const copied = JSON.parse(JSON.stringify(p));
console.log(copied instanceof Person); // false —— 已退化为普通 object
此时 copied 是纯数据对象,无 Person.prototype 关联,所有方法和继承行为全部丢失。
手动恢复原型的可行方式
若需保持原型结构,必须显式重建原型链。常见做法是结合构造函数识别与 Object.setPrototypeOf():
- 先判断原对象的构造函数(注意:需确保构造函数可访问且无污染,如避免跨 iframe 或压缩后丢失名字)
- 用相同构造函数创建新实例(
new obj.constructor(...)),再深拷贝其自有属性 - 对无法调用构造函数的对象(如内置类实例
Map、Date、RegExp),需单独处理 - 递归时对每个子对象重复该逻辑,同时跳过不可构造类型(如
null、原始值、函数)
示例片段:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
function cloneWithProto(obj) {
if (obj === null || typeof obj !== 'object') return obj;
if (obj instanceof Date) return new Date(obj);
if (obj instanceof RegExp) return new RegExp(obj);
if (obj instanceof Array) return obj.map(item => cloneWithProto(item));
const Ctor = obj.constructor;
const cloned = Object.assign(Object.create(Ctor.prototype), obj);
for (let key in cloned) {
if (cloned.hasOwnProperty(key)) {
cloned[key] = cloneWithProto(cloned[key]);
}
}
return cloned;
}
现代替代方案:structuredClone + 后置修复
Chrome 98+/Node.js 17+ 支持 structuredClone(),它能安全复制大多数内置类型(Map、Set、Date、RegExp 等),但仍不保留自定义原型。
可在 structuredClone 基础上补充原型修复:
- 序列化前记录对象的
constructor.name和Object.getPrototypeOf(obj)(需注意 Symbol 属性和不可枚举属性仍会丢失) - 克隆后,用
Object.setPrototypeOf(cloned, originalProto)恢复原型 - 仅适用于原型链简单、无私有字段(
#field)、无闭包绑定方法的场景
不推荐但需知的边界情况
某些模式天然无法深拷贝并保持原型完整:
- 含闭包或私有字段(
#name)的类实例:私有状态无法被外部访问,也无法复制 - 函数对象本身:即使设了原型,
Function.prototype不等于自定义原型,且函数体不可靠序列化 - DOM/BOM 对象(如
Element、Window):不能被任意克隆,structuredClone明确拒绝 - 循环引用 + 自定义原型:需在遍历中维护映射表,否则易栈溢出或原型错位
真正需要原型保全的场景,往往更适合用工厂函数、实例复用或状态解耦设计,而非依赖拷贝。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










