JavaScript原生不支持多重继承,但可通过混入(mixin)、组合或委托模拟:用Object.assign浅拷贝方法到原型,或用高阶函数封装混入逻辑,或以ES6类工厂链式增强,本质是组合而非真正多继承。

JavaScript 原生不支持多重继承(即一个子类同时继承多个父类),因为每个对象只有一个 [[Prototype]] 链,无法指向多个原型。但可以通过组合、混入(mixin)或委托等方式模拟多重继承的效果。核心思路是:**不靠原型链“同时继承”,而是把多个父类的方法和属性“复制”或“委托”到子类或其实例上**。
用 Object.assign 实现属性与方法的浅拷贝混入
这是最轻量、最常用的替代方案,适合复用工具型方法(如事件管理、序列化、校验等):
- 将多个“能力对象”的自有属性和方法一次性合并到子类的 prototype 或实例上
- 不会影响原型链结构,也不改变继承关系
- 注意:只做浅拷贝,对嵌套对象或函数内部的
this绑定需额外处理
示例:
const Eventable = { on() { /*...*/ }, emit() { /*...*/ } };<br>const Serializable = { toJSON() { return JSON.stringify(this); } };<br><br>function User(name) { this.name = name; }<br>// 混入两个能力<br>Object.assign(User.prototype, Eventable, Serializable);<br><br>const u = new User('Alice');<br>u.on('login', () => console.log('logged in'));<br>console.log(u.toJSON()); // {"name":"Alice"}
用函数式 mixin 封装可复用的混入逻辑
避免每次手动 Object.assign,把混入行为抽象成高阶函数:
立即学习“Java免费学习笔记(深入)”;
- 接收目标构造函数和任意数量的能力对象作为参数
- 自动遍历每个能力对象的自有可枚举属性,并挂载到目标原型
- 支持命名冲突时的覆盖策略(如保留先定义的,或强制覆盖)
示例:
function mixin(target, ...sources) {<br> sources.forEach(source => {<br> Object.getOwnPropertyNames(source).forEach(key => {<br> if (key !== 'constructor') {<br> target.prototype[key] = source[key];<br> }<br> });<br> });<br>}<br><br>mixin(User, Eventable, Serializable);
用寄生组合 + 委托模拟多源方法调用
当需要更精细控制(比如某些方法要动态选择来源、或需保持 this 上下文隔离),可用委托模式:
- 在子类中显式持有多个“父能力”实例(如
this.eventManager = new EventEmitter()) - 子类方法内部调用这些实例的方法,而不是直接混入
- 完全规避原型污染和命名冲突,也便于单元测试和替换依赖
示例:
class Component {<br> constructor() {<br> this.emitter = new EventEmitter();<br> this.serializer = new JSONSerializer();<br> }<br> on(...args) { return this.emitter.on(...args); }<br> toJSON() { return this.serializer.toJSON(this); }<br>}
ES6 class 中的混入写法(推荐现代项目使用)
利用 class 表达式 + 工厂函数实现语法清晰的 mixin 链式调用:
- 每个 mixin 是一个接收父类并返回新类的函数
- 可叠加多个 mixin,形成“类增强链”
- 底层仍是单原型链,但语义上接近多重继承
示例:
const WithEvents = (Base) => class extends Base {<br> on(type, handler) { /*...*/ }<br>};<br><br>const WithStorage = (Base) => class extends Base {<br> save() { /*...*/ }<br>};<br><br>class Model {}<br>class UserModel extends WithEvents(WithStorage(Model)) {}<br><br>const u = new UserModel();<br>u.on('change', () => u.save());
不复杂但容易忽略:所有这些方式都不是真正的多重继承,而是通过组合、复制或委托达成类似效果。选哪种取决于你是否需要运行时动态切换能力、是否在意原型链纯净性、以及团队对可读性和维护性的要求。


















