寄生组合式继承的关键在于清晰分离实例属性与原型方法:父类构造函数初始化实例属性,prototype挂共享方法;子类构造函数先调用parent.call(this)再设自有属性;原型链通过object.create(parent.prototype)和constructor修复两步完成。

构造函数与原型职责分明
父类只做两件事:在构造函数里初始化实例属性(尤其是引用类型),在 prototype 上挂共享方法。不混写,不内联。
- 实例属性(如 this.name、this.items = [])必须写在构造函数内——确保每次 new 都生成新副本
- 方法(如 say()、save())一律定义在 Parent.prototype 上——避免重复创建,节省内存
- 不要在构造函数里定义方法,也不要往 prototype 上塞实例数据
子类构造函数只负责“实”
子类构造函数里只做一件明确的事:调用 Parent.call(this, ...args),把父类的实例初始化逻辑借过来。之后再加自己的属性,顺序不能乱。
- Parent.call(this, name, id) 必须在 this 已绑定、但尚未设置子类特有属性前执行
- 传参严格对齐父类构造签名,不硬编码默认值,保持向上兼容
- 子类自有属性(如 this.level、this.config)写在 call 之后,逻辑边界清晰
原型链设置一步到位,不绕弯
子类原型赋值就两行,不封装、不抽象、不加条件判断——简单即可靠。
- Child.prototype = Object.create(Parent.prototype) —— 创建干净副本,不执行父构造,不污染父原型
- Child.prototype.constructor = Child —— 修复 constructor,让 new Child().constructor === Child
- 不写 inheritPrototype 工具函数,除非项目统一规范强制要求;手写更透明,调试更直接
扩展方法放在原型赋值之后
所有子类自定义方法,都明确写在原型链设置完成之后。这样一眼能看出哪些是继承来的,哪些是自己加的。
- 比如 Child.prototype.run = function() { ... } 放在 constructor 修复之后
- 若需重写父类方法,直接覆盖即可,查找链自然生效:子实例 → Child.prototype → Parent.prototype
- 避免在 Object.create 前就往 Child.prototype 上挂方法,否则会被覆盖丢弃











