javascript应避免继承滥用,转而采用组合式设计:将能力拆分为独立模块按需组装,通过依赖注入实现策略替换,仅在必要时用抽象基类定义稳定骨架。

JavaScript 本身不支持多重继承,原型链又是单线性结构,强行套用“类继承”容易导致逻辑耦合、测试困难、扩展僵硬。真正有效的优化不是换写法,而是换思路:把“这个对象属于哪一类”变成“这个对象需要哪些能力”。
识别继承滥用的典型信号
先别急着重构,看看现有代码是否已在透支继承模型:
- 子类重写了父类大部分方法,却只调用 super 中的一小段逻辑
- 某个子类完全用不到父类定义的某个字段或方法(比如 PaymentValidator 被所有订单继承,但内部工单根本无需支付)
- 为新增一种业务类型(如“试用订单”),不得不在继承链上加一层,但它和已有类之间没有清晰的“是一个”关系,只是“用到了部分行为”
用函数/对象代替父类,按需组装能力
把原本塞在基类里的职责,拆成独立、可替换的模块:
- 把价格计算逻辑抽成 PriceStrategy 接口,提供 DefaultPrice、VIPPrice、BundlePrice 等实现
- 把校验规则封装为 ValidationRule 函数,登录表单用 emailRule + passwordRule,注册表单再加 confirmPasswordRule
- 把请求逻辑交给 useApi 组合式函数,而不是让每个组件去继承一个 BaseNetworkComponent
通过构造函数或工厂函数注入依赖
避免在类内部 new 实例或硬编码逻辑分支,把选择权交给调用方:
- 创建服务实例时传入具体策略:new OrderService(new VIPPriceCalculator(), new RedisInventoryChecker())
- 单元测试时直接传入模拟实现:new OrderService(stubPrice, mockInventory)
- 运行时根据环境切换:process.env.NODE_ENV === 'production' ? new SentryLogger() : new ConsoleLogger()
保留继承仅用于极少数稳定骨架
不是彻底禁用,而是大幅收窄使用范围:
- 仅当多个类确实共用不可变流程(如统一事务包装、标准错误格式化、固定生命周期钩子)时,才用抽象基类
- 基类中不放业务判断,只留模板方法和空钩子;所有分支逻辑下沉到组合进来的策略对象里
- 例如:BaseOrderProcessor 只定义 execute() 模板,实际的价格、库存、通知动作全由注入的组件执行
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











