子类原型的constructor丢失会破坏类型判断、序列化和this.constructor语义链,根本原因是重写child.prototype后新对象缺失自有constructor属性;需在new parent()、字面量赋值或object.create后显式修复,并推荐用object.defineproperty确保writable、configurable、enumerable符合规范。

子类原型的 constructor 丢失不是小问题,而是会直接破坏类型判断、序列化逻辑和 this.constructor 调用的语义链。根本原因在于:只要重写了 Child.prototype,原生的 constructor 属性就没了——它原本是 Child.prototype 自身的自有属性,不是从 Object.prototype 继承来的。
为什么重写原型后 constructor 就没了
当你写 Child.prototype = new Parent() 或 Child.prototype = { method() {} },相当于用一个全新对象替换了默认原型。这个新对象没有 constructor 属性,引擎就会顺着原型链往上找,最终落到 Parent.prototype.constructor 或 Object.prototype.constructor,导致 new Child().constructor === Parent 或 Object。
三种常见重写场景及修复方式
-
用 new Parent() 设置原型:这是原型链继承最常用方式,但必须紧跟一行修复:
Child.prototype.constructor = Child; -
用字面量对象赋值:如
Child.prototype = { say() {} };,此时对象连原型链都断了,除了补constructor,还得手动挂上__proto__或用Object.setPrototypeOf(Child.prototype, Parent.prototype) -
用 Object.create(Parent.prototype):更规范的做法,但依然缺失自有
constructor,所以仍需显式设置:Child.prototype.constructor = Child;
更安全的写法:用 Object.defineProperty
直接赋值 .constructor 有被意外覆盖的风险(比如属性可写、可枚举)。推荐用 Object.defineProperty 定义,确保语义稳定:
Child.prototype = Object.create(Parent.prototype);
Object.defineProperty(Child.prototype, 'constructor', {
value: Child,
writable: true,
configurable: false,
enumerable: false
});
这样定义的 constructor 不会出现在 for...in 循环里,也不易被误改,符合规范对构造器标识的预期。
验证是否修好了
修复后务必验证两件事:
-
new Child().constructor === Child返回true -
new Child() instanceof Child和new Child() instanceof Parent都为true
如果只满足前者但后者为 false,说明原型链没接上;如果两者都不满足,大概率是 constructor 没设对或设在了错误对象上。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











