寄生组合式继承的设计目标是只调用一次父类构造函数、隔离实例属性、复用原型方法;其边界情况源于开发者偏离该意图,需守住不触发父类构造函数设原型、保留call初始化、用干净原型桥接三大逻辑。

寄生组合式继承本身设计目标明确:只调用一次父类构造函数、隔离实例属性、复用原型方法。它的“边界情况”不是语法报错,而是开发者在实际使用中容易偏离这个设计意图的几类典型场景。处理关键在于守住三个核心逻辑——不触发父类构造函数设原型、保留 call 初始化、用干净原型桥接。
父类原型为空或不可枚举时
如果 SuperType.prototype 是空对象({})或通过 Object.defineProperty 设置了 enumerable: false 的方法,Object.create(SuperType.prototype) 仍能正确继承,但调试时可能看不到方法列表。
- 确保父类方法确实定义在原型上,而不是构造函数内(否则无法被继承)
- 检查是否意外覆盖了
SuperType.prototype,比如赋值为null或Object.create(null)—— 这会导致子类原型链断开 - 可用
console.dir(SubType.prototype)查看__proto__是否指向SuperType.prototype
父类构造函数有副作用或依赖 this 绑定
若 SuperType 构造函数里执行了 DOM 操作、发起请求、或依赖 this 必须是新实例(比如内部用了 new.target),那在 SubType 构造函数中调用 SuperType.call(this, ...) 是安全的;但绝不能在设置原型时隐式触发它。
- 禁止任何形式的
new SuperType()或SuperType()出现在原型赋值路径中 - 若父类构造函数必须校验调用方式(如只允许
new),可加 guard:if (!(this instanceof SuperType)) throw new Error('SuperType must be called with new'),并在子类中用Reflect.construct替代call(需兼容性考量)
多层继承链中 constructor 指向丢失
当 A → B → C 多级继承时,每级都需修复 .constructor。仅靠一次 inheritPrototype(B, A) 不够,C 继承 B 时也要再调一次。
- 每次调用
inheritPrototype(Child, Parent)都应包含childPrototype.constructor = Child - 避免手动写
SubType.prototype.constructor = SubType,容易遗漏;封装函数里统一处理更可靠 - ES6 class 转译输出(如 Babel)已自动处理该问题,手写继承时需格外注意
父类使用 Symbol 或 getter/setter 定义原型成员
Object.create(SuperType.prototype) 能正确继承所有原型上的 Symbol 属性和 accessor,但不会复制构造函数内的实例 Symbol 属性。
- Symbol 方法或 getter 若定义在原型上,继承后可直接使用
- 若父类在构造函数中用
this[Symbol.iterator] = ...,这属于实例属性,必须靠SuperType.call(this)触发才会有,无需额外操作 - 检查继承后能否正常调用
instance[Symbol.iterator]()或读写instance.prop(对应 setter)











