深拷贝应通过 Object.getPrototypeOf() 和 Object.create() 保持原型链,而非依赖 constructor;constructor 不可靠且非原型载体,正确做法是重建 [[Prototype]] 并复制自有属性。

JavaScript 中深拷贝不能也不应该依赖 constructor 来保持或恢复原型链。这是个常见误区,也是深拷贝中一个关键陷阱。
constructor 属性并不可靠:
-
Object.create(null)创建的对象根本没有constructor; - 原型被修改后(如
obj.__proto__ = {}),obj.constructor可能指向错误构造器; - 箭头函数、内置对象(如
Array、Date)的constructor虽存在,但直接调用obj.constructor()可能失败或产生意外行为(比如RegExp.prototype.constructor === RegExp,但new ({}).constructor()会报错); - 用户可能手动篡改
constructor,使其失去语义意义。
真正需要保留的是对象的 [[Prototype]] 内部槽(即原型链),而不是 constructor 本身。constructor 只是原型上的一个属性,它只是“指示”了谁创建了这个实例,但不是原型链的载体。
所以,正确做法是:
立即学习“Java免费学习笔记(深入)”;
- 用
Object.getPrototypeOf(obj)获取原对象的真实原型; - 用
Object.create(proto)创建新对象,并显式设置其[[Prototype]]; - 再把原对象的自有属性(含不可枚举、getter/setter)复制过去,用
Object.getOwnPropertyDescriptors()+Object.defineProperties()。
例如:
function deepClone(obj, seen = new WeakMap()) {
if (obj === null || typeof obj !== 'object') return obj;
if (seen.has(obj)) return seen.get(obj);
// 关键:获取并重建原型链,不碰 constructor
const proto = Object.getPrototypeOf(obj);
const clone = Object.create(proto);
seen.set(obj, clone);
// 复制所有自有属性(包括不可枚举、访问器)
const descriptors = Object.getOwnPropertyDescriptors(obj);
for (const key in descriptors) {
const desc = descriptors[key];
if ('value' in desc) {
clone[key] = deepClone(desc.value, seen);
} else {
Object.defineProperty(clone, key, {
get: desc.get ? () => deepClone(desc.get.call(obj), seen) : undefined,
set: desc.set ? (v) => desc.set.call(clone, deepClone(v, seen)) : undefined,
enumerable: desc.enumerable,
configurable: desc.configurable
});
}
}
return clone;
}对 Date、RegExp 等内置类型,也应走相同逻辑:
-
new Date(obj.getTime())→ 新实例自动继承Date.prototype; -
new RegExp(obj.source, obj.flags)→ 自动继承RegExp.prototype; - 它们的
constructor是原型上自然携带的,无需手动赋值或调用。
总结一句话:
深拷贝要保的是 [[Prototype]],不是 constructor;修复原型链靠 Object.create(),不是 obj.constructor()。
constructor 是结果,不是手段。


















