JavaScript 可通过运行时检查模拟接口契约:在父类 constructor 中验证子类是否实现必需方法,未实现则抛错;用 getter 封装契约校验逻辑;配合命名规范与 JSDoc 提升可维护性。

JavaScript 本身不支持 interface 或 abstract class 的语法,所以无法像 TypeScript 那样在运行时强制约束子类必须实现某些方法。但你可以用 class 语法 + 运行时检查的方式,模拟接口契约效果,让子类行为更可控、更可预期。
用构造函数抛错,提示“未实现必需方法”
在父类 constructor 中检查子类是否提供了关键方法,没提供就直接报错:
- 父类不写具体实现,只定义“契约点”,比如
process()、validate() - 在 constructor 里判断
typeof this.process !== 'function',不满足就 throw - 这样只要 new 子类实例,就会立刻暴露缺失逻辑,避免后期静默失败
示例:
复制代码运行即可验证
class Processor {<br> constructor() {<br> if (typeof this.process !== 'function') {<br> throw new Error('子类必须实现 process() 方法');<br> }<br> }<br>}<br><br>class CsvProcessor extends Processor {<br> // ✅ 正确:实现了契约方法<br> process(data) { return data.split(','); }<br>}<br><br>new CsvProcessor(); // 正常<br>// new class extends Processor {}(); // 报错
用 getter 暴露契约状态,统一校验入口
把“是否合规”封装成只读属性,方便调试和日志追踪:
- 定义
get isContractReady(),内部检查多个方法是否存在 - 在关键流程(如
run())开头调用它,失败则提前退出 - 比零散 if 判断更集中,也便于后续加类型提示或单元测试断言
示例:
class Task {<br> get isContractReady() {<br> return typeof this.execute === 'function' &&<br> typeof this.cleanup === 'function';<br> }<br><br> run() {<br> if (!this.isContractReady) {<br> throw new Error('任务类未满足执行契约');<br> }<br> this.execute();<br> this.cleanup();<br> }<br>}
配合文档与命名约定,降低误用概率
运行时检查是兜底,但好设计要靠显性引导:
- 父类名加
Base或Abstract前缀(如DataLoaderBase),提醒开发者这是模板 - 抽象方法名用动词开头,带明确语义(
parseRawData()而不是doIt()) - 在 JSDoc 里写清楚每个方法的参数、返回值、副作用,IDE 能自动提示
例如:
/** <br> * @abstract 必须由子类实现 <br> * @param {string} raw - 原始响应文本 <br> * @returns {Object} 解析后的结构化数据 <br> */<br>parseRawData(raw) {}
注意边界:这不是真正的接口,只是轻量契约
这种做法不改变 JS 运行机制,也不提供编译期检查:
- 它不能防止子类把
process()写成空函数,需靠测试覆盖 - 不支持多继承式接口组合,一次只能“继承一个契约基类”
- 如果项目已用 TypeScript,应优先用
abstract class+interface组合,更健壮
纯 JS 场景下,这种方式足够清晰、低侵入、易调试,适合中小型模块的协作规范。











