JavaScript组件设计应以组合替代过深继承:用props.children复用结构、策略对象注入可变逻辑、Hook/混入封装横切能力,并通过三步剪枝法重构冗余继承链。

在 JavaScript 组件设计中,用组合替代过深继承链,核心是把“谁是谁的子类”变成“谁拥有谁的能力”。不靠 extends 拉长原型链,而是让组件通过 props、函数注入、对象持有等方式按需拼装行为。这既避免父类改动引发连锁崩溃,也支持运行时替换逻辑。
用 props.children 和插槽预留内容位置
很多所谓“需要继承”的场景,其实只是想复用容器结构,但内容不确定。这时不用写 BaseList → SearchList → FilteredList,直接用 props.children:
- 父组件只定义结构和样式,内部用 {props.children} 接收任意子内容
- 子组件不再继承,而是作为普通 JSX 传入:
<Card><SearchForm /></Card> - 配合 defaultProps 或 required props 做约束,比继承更轻量、更可控
把可变逻辑抽成策略对象,构造时注入
当多个组件共享类似流程(如表单提交、数据加载),但具体步骤不同(校验规则、API 地址、错误处理),就把这些差异点封装为独立对象:
- 定义
ValidationStrategy、DataLoader等类或工厂函数 - 组件内部持有一个字段,如
this.loader = props.loader || new DefaultLoader() - 调用时统一走
this.loader.fetch(),不关心它怎么实现 - 测试时可直接传入 mock 实例,无需模拟整个父类链
用混入(Mixin)或组合函数替代中间层类
像 Loggable、Resizable、Draggable 这类横切能力,不该靠继承 BaseComponent → LoggableComponent → ResizableComponent 来叠加。改用更直接的方式:
立即学习“Java免费学习笔记(深入)”;
- 用
Object.assign(this, loggerMixin)把日志方法挂到实例上 - 在 React 中写
useLogger()、useDrag()等 Hook,逻辑隔离、无耦合 - Vue 3 的 Composition API 同理,把功能组织成可导出、可复用的函数块
- 避免命名冲突:混入属性加前缀(如
_logError),或用 Symbol 作私有键
重构已有继承链:三步剪枝法
面对已有的多层继承(如 A → B → C → D),不要重写全部,优先做减法:
- 识别哪一层没新增实质状态或模板,只是转发方法——删掉它,把共用方法提成工具函数
- 把子类中反复重写的钩子方法(如
beforeSubmit)改为接收回调函数 props - 将原本通过
super.xxx()调用的通用逻辑,改为组件内调用sharedUtils.xxx()


















