JavaScript原型继承需遵循职责分离、修正constructor、避免重复调用父构造函数三大原则:构造函数初始化实例属性,原型定义共享方法;用Object.create(Parent.prototype)替代new Parent()并修复constructor;现代项目优先使用class语法。

JavaScript 原型继承本身没有官方强制规范,但长期实践已形成被广泛接受的代码约定。核心目标是:避免原型污染、保证属性/方法归属清晰、防止构造函数重复调用、明确实例与原型的职责边界。
构造函数与原型的职责分离
构造函数只负责初始化**实例专属属性**(尤其是引用类型),原型对象只承载**可复用的方法和不可变的默认值**。
- ✅ 推荐写法:在 构造函数内 初始化
this.name、this.items = []等; - ✅ 推荐写法:在 prototype 上 定义
sayName()、toString()等方法; - ❌ 避免:把数组、对象字面量直接写在
prototype上(如Child.prototype.cache = {}),否则所有实例共享; - ❌ 避免:在
prototype中调用this初始化引用类型(它会在首次访问时才执行,且影响所有实例)。
继承链搭建必须修正 constructor
使用 Child.prototype = new Parent() 后,Child.prototype.constructor 会指向 Parent,这会破坏 instanceof 判断和调试体验,必须手动修复。
- ✅ 必须加上:
Child.prototype.constructor = Child; - ✅ 更稳妥写法(ES5+):
Object.defineProperty(Child.prototype, 'constructor', { value: Child, writable: true, configurable: true, enumerable: false }); - ❌ 不要省略,也不要写成
Child.prototype.constructor = Parent。
组合继承中避免父构造函数执行两次
经典组合继承(构造函数继承 + 原型链继承)会导致父类构造函数被调用两次:一次在 Parent.call(this),一次在 new Parent()。虽不影响功能,但浪费资源且可能引发副作用(如发请求、改状态)。
立即学习“Java免费学习笔记(深入)”;
- ✅ 推荐替代:用
Object.create(Parent.prototype)替代new Parent()设置子类原型; - ✅ 示例:
Child.prototype = Object.create(Parent.prototype);—— 只建立原型链接,不执行父构造函数; - ✅ 再补上:
Child.prototype.constructor = Child;; - ✅ 构造函数内仍保留
Parent.call(this, ...),确保实例属性正确初始化。
优先使用 ES6 class 语法(现代项目)
尽管底层仍是原型机制,class 语法提供了更清晰、更安全的继承表达,并自动处理 constructor 修复、严格模式、重复定义报错等细节。
- ✅ 推荐:
class Child extends Parent { constructor(...args) { super(...args); } }; - ✅
super()确保父类构造函数只执行一次,且上下文正确; - ✅ 方法定义天然在原型上,无需手动挂载;
- ⚠️ 注意:不要混用
class和手动操作__proto__或prototype,易造成行为不一致。


















