闭包是javascript中实现私有状态和封装逻辑的天然工具,通过内部保存state、对外暴露有限方法(如send),可避免全局污染并清晰管控状态切换;支持监听、副作用注入、状态冻结及class封装增强可维护性。

闭包是 JavaScript 中实现私有状态和封装逻辑的天然工具,用它设计状态机可以避免全局变量污染,同时让状态切换和行为响应更清晰可控。
用闭包封装状态与转换逻辑
核心思路是:闭包内部保存当前状态(state),对外只暴露有限的方法(如 send 或 transition),所有状态变更和副作用都在闭包内完成,外部无法直接修改状态。
例如,一个简单的“加载-成功-失败”三态机:
function createLoader() {
let state = 'idle'; // 私有状态
return {
send(action) {
if (action === 'start' && state === 'idle') {
state = 'loading';
console.log('开始加载');
} else if (action === 'resolve' && state === 'loading') {
state = 'success';
console.log('加载成功');
} else if (action === 'reject' && state === 'loading') {
state = 'error';
console.log('加载失败');
}
// 其他非法转换被静默忽略
},
getState() {
return state;
}
};
}
const loader = createLoader();
loader.send('start'); // 开始加载
loader.send('resolve'); // 加载成功
console.log(loader.getState()); // 'success'
支持状态监听与副作用注入
实际项目中常需在状态变化时触发 UI 更新或日志记录。可在闭包内维护回调列表,并在每次状态变更后统一通知:
- 用数组存储
onStateChange回调函数 - 每次
send执行完更新状态后,调用所有监听器,传入旧状态和新状态 - 监听器可自由处理副作用,不影响状态机核心逻辑
示例扩展:
function createStateMachine(initialState, config) {
let state = initialState;
const listeners = [];
function send(event) {
const prevState = state;
const nextState = config[state]?.[event];
if (nextState !== undefined) {
state = nextState;
listeners.forEach(cb => cb(prevState, nextState));
}
}
return {
send,
getState: () => state,
onStateChange: (cb) => listeners.push(cb)
};
}
// 使用:定义状态转移表
const fsm = createStateMachine('idle', {
idle: { start: 'loading' },
loading: { resolve: 'success', reject: 'error' },
success: { reset: 'idle' },
error: { retry: 'loading', reset: 'idle' }
});
fsm.onStateChange((from, to) => {
console.log(`状态从 ${from} → ${to}`);
});
fsm.send('start'); // 状态从 idle → loading
避免常见陷阱:状态不可变与边界检查
闭包虽能隐藏状态,但若直接修改对象属性或数组,仍可能被意外篡改。建议:
- 状态值尽量用原始类型(string、number、boolean)或冻结对象:
Object.freeze({}) - 在
send中加入严格的状态合法性校验,比如检查 event 是否被当前状态支持 - 不返回内部状态引用,
getState()返回副本或只读视图
例如防止外部篡改状态对象:
function createSafeFSM(initialState) {
let state = { value: initialState };
Object.freeze(state); // 冻结初始状态对象
return {
send(next) {
state = Object.freeze({ value: next }); // 每次新建冻结对象
},
getState() {
return { ...state }; // 返回浅拷贝,避免暴露引用
}
};
}
配合 class 封装提升可读性(可选)
如果需要更多能力(如初始化逻辑、异步动作、历史记录),可用 class 包裹闭包逻辑,保持构造函数私有化,方法仍依托闭包作用域:
class FSM {
#state;
#transitions = new Map();
constructor(initialState) {
this.#state = initialState;
}
addTransition(from, event, to, effect = () => {}) {
const rules = this.#transitions.get(from) || [];
rules.push({ event, to, effect });
this.#transitions.set(from, rules);
}
send(event) {
const rules = this.#transitions.get(this.#state) || [];
const rule = rules.find(r => r.event === event);
if (rule) {
rule.effect();
this.#state = rule.to;
}
}
get state() {
return this.#state;
}
}
这种写法兼顾了闭包的封装性和 class 的组织性,适合中等复杂度的状态管理场景。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











