javascript class 不支持多继承,但可通过 mixin 模式实现:用 object.assign 将多个对象方法混入原型;封装 applymixins 函数可处理不可枚举属性并跳过 constructor;状态型 mixin 需在构造函数中初始化实例属性。

JavaScript 的 class 本身不原生支持多继承,但可以通过“mixin”模式将多个对象的方法和属性“混入”到一个类中。核心思路是:**在类定义前或构造函数中,把目标对象的可枚举方法复制到类的原型上**。
用 Object.assign 混入到原型(推荐)
这是最简洁、常用的方式,适合混入纯方法的对象(无状态 mixin):
// 定义两个 mixin 对象
const Flyable = {
fly() { console.log('Flying...'); }
};
const Swimmable = {
swim() { console.log('Swimming...'); }
};
// 定义主类
class Duck {
quack() { console.log('Quack!'); }
}
// 将多个 mixin 的方法复制到 Duck.prototype
Object.assign(Duck.prototype, Flyable, Swimmable);
// 使用
const duck = new Duck();
duck.quack(); // Quack!
duck.fly(); // Flying...
duck.swim(); // Swimming...
封装成可复用的 mixin 函数
避免重复写 Object.assign,可以封装一个高阶函数:
将一个或多个视频上传至YouTube。当用户想“上传到YouTube”“发YouTube”“批量上传”“upload to YouTube”“post videos to YouTube”或发布到YouTube时使用此技能。
function applyMixins(targetClass, ...mixins) {
mixins.forEach(mixin => {
Object.getOwnPropertyNames(mixin).forEach(name => {
if (name !== 'constructor') {
targetClass.prototype[name] = mixin[name];
}
});
});
}
// 使用
class Bird {}
applyMixins(Bird, Flyable, Swimmable);
- 比
Object.assign更严谨:能处理不可枚举属性(如通过Object.defineProperty定义的) - 跳过
constructor,防止意外覆盖 - 支持任意数量的 mixin,顺序靠后者会覆盖同名方法
在构造函数中混入实例属性(带状态)
如果 mixin 需要初始化实例字段(比如 this.speed = 0),不能只改原型,得在 constructor 中处理:
const Drivable = {
initDrive() {
this.speed = 0;
this.isDriving = false;
},
drive() {
this.isDriving = true;
console.log('Vroom!');
}
};
class Car {
constructor() {
// 手动调用 mixin 初始化逻辑
this.initDrive(); // 来自 Drivable
}
honk() { console.log('Beep!'); }
}
// 还是需要混入方法
Object.assign(Car.prototype, Drivable);
- 状态型 mixin 需要“两步走”:构造函数里调用初始化方法 + 原型上混入方法
- 也可把初始化逻辑写进一个私有方法(如
_initDrivable),避免污染公共 API
注意继承链与 instanceof
Mixin 不改变类的继承关系:
-
duck instanceof Duck→ true -
duck instanceof Flyable→ false(Flyable是普通对象,不是构造函数) - 若需类型检查,可用
duck.fly存在性判断,或用 Symbol.hasInstance 自定义(较少见)
不复杂但容易忽略。关键是分清:方法混入原型,状态初始化放构造函数,组合方式灵活但别破坏原有语义。










