javascript通过运行时检查模拟抽象类:禁止直接实例化基类,并强制子类重写抽象方法;配合jsdoc或typescript可提升开发体验,适用于中等复杂度模块解耦。

JavaScript 本身没有原生的抽象类语法,但可以通过约定 + 运行时检查的方式模拟抽象类行为,从而定义清晰、强制性的接口规范。核心思路是:让基类禁止被直接实例化,并要求子类必须实现特定方法。
用构造函数抛错模拟“不可实例化”
在抽象类的构造函数中主动检测是否被直接调用(而非通过 super() 继承调用),若是则抛出错误:
class Shape {
constructor() {
if (this.constructor === Shape) {
throw new Error('Shape 是抽象类,不能直接实例化');
}
}
// 抽象方法:不提供实现,仅声明
getArea() {
throw new Error('子类必须实现 getArea 方法');
}
getPerimeter() {
throw new Error('子类必须实现 getPerimeter 方法');
}
}
子类必须重写抽象方法(运行时保障)
JavaScript 不做编译期检查,所以靠方法体内抛错来强制子类覆盖。只要子类没重写,调用时立刻报错,提示明确:
- 子类继承后,若未重写
getArea,调用new Circle().getArea()就会失败 - 这相当于把“接口契约”延迟到首次使用时验证,比完全放任更可靠
- 配合 JSDoc 或 TypeScript 可进一步提升开发体验(如标注
@abstract)
配合工厂或模板方法增强规范性
抽象类可封装通用流程,把变化点留给子类实现,形成稳定接口+灵活扩展的组合:
class DataProcessor {
constructor() {
if (this.constructor === DataProcessor) {
throw new Error('DataProcessor 是抽象类');
}
}
process(data) {
const cleaned = this.clean(data); // 由子类实现
const transformed = this.transform(cleaned); // 由子类实现
return this.format(transformed); // 由子类实现
}
clean() { throw new Error('clean 必须由子类实现'); }
transform() { throw new Error('transform 必须由子类实现'); }
format() { throw new Error('format 必须由子类实现'); }
}
class JSONProcessor extends DataProcessor {
clean(data) { return data.trim(); }
transform(jsonStr) { return JSON.parse(jsonStr); }
format(obj) { return JSON.stringify(obj, null, 2); }
}
这样,所有处理器对外都统一暴露 process(),内部逻辑由子类按规范填充 —— 接口一致,实现可插拔。
注意边界:这不是类型系统,而是协作契约
这种模拟不提供静态类型检查或 IDE 自动补全(除非配 TS),它的价值在于:
- 用最小成本建立团队间的方法命名与职责约定
- 运行时报错比静默失败更容易定位设计漏洞
- 比纯文档或注释更具执行约束力
适合中等复杂度的模块解耦,比如渲染器、策略集、数据适配器等有明确共性行为的场景。










