团队开发应禁用非必要继承,统一采用组合、配置、策略模式等低耦合方案;仅当满足严格“is-a”语义且需共用状态生命周期时,才允许ES6 class extends,并强制super()首行调用、@virtual标注及父类constructor无虚方法调用。

团队开发中不需要统一“继承标准”,而应统一不依赖继承的协作规范。JS 继承本身不是接口契约,过度设计继承链反而增加耦合、掩盖职责、抬高理解成本。真正需要规范的是:何时用、怎么写、谁负责维护。
明确禁止使用继承的场景
以下情况一律禁用 class extends 或手动原型链:
- 只是为了复用一两个工具方法(应抽成独立函数或 hooks)
- 父类和子类语义上无“is-a”关系(比如 “Button extends APIRequest”)
- 跨模块/跨包定义父子类(导致隐式强依赖,发布和测试难解耦)
- 父类含副作用逻辑(如自动初始化、全局监听、定时器),子类无法控制生命周期
允许继承时的硬性编码约束
仅当满足“子类是父类的特化形态,且需共用核心状态与行为生命周期”时才可继承,并强制遵守:
- 所有继承必须基于 ES6 class + extends,禁用 __proto__、Object.setPrototypeOf 等手动原型操作
- 子类 constructor 中 super() 必须为第一行,且参数需显式声明(不允许 super(...arguments))
- 父类方法若允许被重写,必须在 JSDoc 中标注 @virtual;禁止未声明就覆盖父类方法
- 父类不得在 constructor 中调用 this 上的非 final 方法(避免子类尚未初始化就触发重写逻辑)
替代继承的团队推荐方案
绝大多数复用需求,优先采用更清晰、更易测试、更利于并行开发的方式:
- 组合优于继承:用字段持有依赖对象(如 class Form { validator = new EmailValidator(); })
- 配置驱动行为:通过 options 参数控制差异(如 new Chart({ type: 'bar', animate: true }))
- 策略模式封装变化点:将不同逻辑抽为独立函数或类,由主类注入使用
- hooks / useXxx 自定义逻辑:在 React/Vue 场景下,用函数式抽象代替类层次
文档与评审中的继承检查项
每次 CR(Code Review)必须确认:
- 该继承是否在领域模型图中已有明确定义(如 UML 类图或领域术语表)
- 父类是否已打上 @stable 标签,且其 public API 在最近 3 个版本未变更
- 是否存在对应单元测试,覆盖子类 override 行为 + 父类不变契约(如 “getName() 始终返回字符串”)
- CI 流程中是否启用 ESLint 规则 no-useless-constructor 和 no-dupe-class-members











