闭包通过作用域隔离、显式入口和变更校验模拟单向数据流:封装状态为私有,仅暴露getState()返回不可变快照、transition(action)作为唯一修改入口,并内置allowedTransitions校验逻辑强制状态合法迁移。

闭包本身不直接构成单向数据流,但它能为局部组件状态提供“受控变更”的底层机制——通过作用域隔离 + 显式入口 + 变更校验,模拟出单向流动的约束效果。
闭包构建“只读状态 + 唯一变更通道”
在组件内部用闭包封装当前状态和允许的变更规则,外部无法直接读写原始值,只能调用预设方法触发状态迁移。
- 状态变量(如 state)定义在闭包内,不暴露引用
- 只提供 getState() 返回不可变快照(例如用
Object.freeze或结构化克隆) - 只暴露 transition(action) 作为唯一修改入口,且内置路径校验逻辑
校验逻辑必须内聚在闭包中
合法的状态变更不是靠文档约定,而是由闭包内部的流转表和判断逻辑强制保障。比如订单从 draft 不可直接跳到 confirmed,这个限制写死在闭包作用域里,调用方绕不开。
- 允许的转换关系(allowedTransitions)是闭包私有常量,不可篡改
-
transition() 执行前检查
allowedTransitions[state]?.includes(to) - 非法调用直接抛错,不会静默失败或留下中间态
避免闭包“破功”的关键细节
一旦把内部对象原样返回,单向控制就失效了。必须阻断外部对状态的任意修改能力。
- ❌ 错误:返回
{ state }—— 外部可改obj.state = 'hacked' - ❌ 错误:返回数组/对象引用 —— 外部可
push、assign、delete - ✅ 正确:返回
JSON.parse(JSON.stringify(data))(纯数据) - ✅ 正确:返回
Object.freeze({ ... })或只读代理
与真正单向数据流框架的区别
闭包实现的是局部、轻量、无框架依赖的状态守门员,它不解决跨组件通信或时间旅行调试等问题。它适合按钮状态机、表单步骤控制器、动画阶段管理等边界清晰的小型状态场景。
若需全局统一调度、日志追踪、热重载支持,则应选用 ReSwift、Redux 或 Combine 这类带完整单向链路(Action → Reducer → Store → View)的方案。










