javascript无原生abstract class/interface,但可通过构造函数检查、占位错误、运行时校验及jsdoc模拟;typescript提供编译期interface/abstract class支持,推荐工程实践。

JavaScript 本身没有原生的 abstract class 或 interface 关键字(ES2024 仍如此),但可以通过约定、运行时检查和类设计模式来有效模拟这两种面向对象概念,达到约束子类行为、明确契约的目的。
用抽象类模拟:强制子类实现特定方法
核心思路是:在父类构造函数中检测子类是否实现了规定方法,未实现则抛出错误。同时,抽象方法本身可抛出提示性错误,防止被直接调用。
- 定义一个基类,在其
constructor中检查this上是否存在必需的方法(如render、validate) - 把抽象方法写成“占位实现”,例如
render() { throw new Error('render() must be implemented by subclass'); } - 子类必须
extends该基类,并在自身中定义同名方法,否则实例化时就会报错
示例:
class Shape {
constructor() {
if (this.constructor === Shape) {
throw new TypeError('Shape is an abstract class and cannot be instantiated');
}
if (typeof this.render !== 'function') {
throw new TypeError('Subclass must implement render()');
}
}
render() {
throw new Error('render() must be implemented');
}
}
<p>class Circle extends Shape {
render() {
return 'Drawing a circle';
}
}</p><p>// new Shape(); // ❌ 报错:抽象类不能实例化
console.log(new Circle().render()); // ✅ "Drawing a circle"
</p>
用接口模拟:通过鸭子类型 + 类型检查工具(如 TypeScript)或运行时校验
JavaScript 的接口本质是“行为契约”。纯 JS 中无法编译期检查,但可通过以下方式逼近:
- 运行时接口校验函数:写一个辅助函数,接收对象和期望的方法名数组,逐一检查是否存在且为函数
- 工厂/构造器守卫:在创建依赖某接口的对象时,先校验传入对象是否满足接口要求
-
配合 JSDoc + IDE 支持:用
@implements注释提示开发工具(VS Code 可识别),增强可读性和编辑体验
示例(运行时接口检查):
function implementsInterface(obj, methods) {
for (const method of methods) {
if (typeof obj[method] !== 'function') {
throw new TypeError(`Object missing required interface method: ${method}`);
}
}
}
<p>// 定义“Drawable”接口语义
const Drawable = ['render', 'hide', 'show'];</p><p>class Button {
render() { return 'button'; }
show() { /<em> ... </em>/ }
hide() { /<em> ... </em>/ }
}</p><p>implementsInterface(new Button(), Drawable); // ✅ 通过
// implementsInterface({ render() {} }, Drawable); // ❌ 缺少 hide/show
</p>
结合 TypeScript 获得真正接口支持
若项目允许使用 TypeScript(JS 的超集),可直接使用 interface 和 abstract class,编译期即检查,零运行时开销,是最推荐的工程实践。
interface Drawable { render(): string; hide(): void; show(): void; }abstract class Shape { abstract area(): number; }- TypeScript 编译器会确保类
implements Drawable或extends Shape时满足全部要求
编译后仍是标准 JavaScript,不引入运行时依赖。
实际建议:轻量约定优于复杂模拟
在纯 JavaScript 项目中,过度模拟抽象类或接口可能增加维护成本。更务实的做法是:
- 用清晰命名(如
BaseValidator、LoggerLike)暗示抽象意图 - 在文档或 JSDoc 中明确标注“此方法必须由子类覆盖”或“预期对象需具备 X/Y/Z 方法”
- 关键路径做轻量校验(如构造器里
if (!options.handle) throw),而非全量接口扫描 - 优先用组合(composition)代替继承,减少对抽象结构的依赖
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











