JavaScript 通过继承+方法重写实现运行时多态:父类定义接口(如area),子类覆盖实现,调用时自动执行对应版本;不支持编译期方法重载,可用剩余参数模拟但非真正多态;组合策略模式提供更灵活的多态替代方案。

JavaScript 中的 class 语法本身不直接提供像 Java 或 C++ 那样的“编译期多态”(如方法重载),但可以通过继承 + 方法重写 + 运行时动态调用自然实现面向对象中最核心的多态特性:**同一接口,不同实现,运行时根据实际类型决定行为**。
用 extends 和 override 模拟运行时多态
这是最常用、最符合直觉的方式:父类定义通用方法签名,子类按需覆盖(override),调用时无需知道具体子类类型。
- 父类中声明方法(可带默认实现或抛出错误,表示“必须由子类实现”)
- 子类用相同方法名重新定义逻辑
- 把不同子类实例存入数组或传给统一函数,调用该方法时自动执行对应子类版本
示例:
class Shape {
area() {
throw new Error('子类必须实现 area 方法');
}
}
<p>class Circle extends Shape {
constructor(radius) {
super();
this.radius = radius;
}
area() {
return Math.PI * this.radius ** 2;
}
}</p><p>class Rectangle extends Shape {
constructor(width, height) {
super();
this.width = width;
this.height = height;
}
area() {
return this.width * this.height;
}
}</p><p>// 多态体现:统一处理,自动分发
const shapes = [new Circle(3), new Rectangle(4, 5)];
shapes.forEach(shape => console.log(shape.area())); // → 28.27..., 20
利用 this.constructor 或 instanceof 做类型感知增强(可选)
当需要在父类方法中“知道自己是哪个子类”时,可用 this.constructor 获取当前实例的真实构造器,或用 instanceof 做轻量判断。这不是多态必需,但能支撑更灵活的策略分支。
立即学习“Java免费学习笔记(深入)”;
-
this.constructor.name可读取子类名(适合调试或简单路由) - 避免在关键逻辑里硬编码
instanceof判断——这会削弱可扩展性;优先用方法重写 - 若必须区分类型(如序列化策略),可封装成 protected 的
getKind()并由子类返回字符串
注意:JavaScript 没有方法重载(Overload)
不能像 Java 那样靠参数个数或类型声明多个同名方法。如果需要类似效果,只能手动检查 arguments 或使用剩余参数 + 类型判断:
- 不推荐:
area(x)和area(x, y)写两个独立方法名(如areaByRadius/areaBySides) - 更合理:统一用
area(...args),内部用args.length或typeof args[0]分支处理 - 但这类“重载模拟”不属于多态范畴,它属于函数内部逻辑分支
组合优于继承时的多态替代方案
当行为差异大、继承链易僵化,可改用“组合 + 策略对象”实现更松耦合的多态:
- 定义统一的行为接口(如
{ calculate: () => number }) - 不同策略对象实现该接口(
CircleStrategy,RectStrategy) - 主类持有一个策略实例,调用
strategy.calculate()—— 替换策略即切换行为 - 这种方式在运行时可动态更换行为,比继承更灵活


















