闭包实现组件状态机的核心是将状态变量和转换逻辑封装在函数作用域内,仅暴露受控操作接口,确保私有性与可维护性。

用闭包实现组件内部状态机,核心是把状态变量和状态转换逻辑封装在函数作用域内,对外只暴露有限的、受控的操作接口。这样既能避免全局污染,又能保证状态不被随意修改,天然契合“私有状态 + 可控行为”的状态机本质。
用闭包封装状态与转换函数
定义一个工厂函数,返回包含当前状态和操作方法的对象。状态变量(如 currentState)被闭包捕获,外部无法直接访问;所有状态变更都必须通过明确的、命名清晰的方法触发:
function createButtonStateMachine() {
let currentState = 'idle'; // 私有状态
return {
getState() {
return currentState;
},
click() {
if (currentState === 'idle') {
currentState = 'loading';
} else if (currentState === 'loading') {
currentState = 'success';
} else if (currentState === 'success') {
currentState = 'idle';
}
return this;
},
reset() {
currentState = 'idle';
return this;
}
};
}
const button = createButtonStateMachine();
console.log(button.getState()); // 'idle'
button.click().click();
console.log(button.getState()); // 'success'
支持状态迁移规则与副作用
真实场景中,状态跳转常需校验合法性、触发回调或异步操作。可在闭包内维护迁移表(transitions)和钩子(onEnter),让状态逻辑更可维护:
function createFetchStateMachine() {
let state = 'idle';
const handlers = {
idle: { onEnter: () => console.log('Ready to fetch') },
loading: { onEnter: () => console.log('Fetching...') },
success: { onEnter: () => console.log('Done!') },
error: { onEnter: () => console.log('Oops!') }
};
const transitions = {
idle: { fetch: 'loading' },
loading: { resolve: 'success', reject: 'error' },
success: { reset: 'idle' },
error: { reset: 'idle' }
};
return {
getState: () => state,
dispatch(action) {
const next = transitions[state]?.[action];
if (next !== undefined) {
state = next;
handlers[state]?.onEnter?.();
}
return this;
}
};
}
结合 DOM 组件做实际封装
在轻量级 UI 组件中,闭包状态机可直接绑定 DOM 元素行为。例如按钮点击后禁用、显示加载文字、再恢复 —— 所有状态和 DOM 更新都在闭包内协调:
<code>function createToggleableButton(el) {
let state = 'idle';
const updateUI = () => {
el.disabled = state === 'loading';
el.textContent =
state === 'idle' ? 'Click me' :
state === 'loading' ? 'Loading...' :
state === 'success' ? 'Done!' : 'Error';
};
updateUI();
el.addEventListener('click', () => {
if (state === 'idle') {
state = 'loading';
updateUI();
// 模拟异步请求
setTimeout(() => {
state = Math.random() > 0.2 ? 'success' : 'error';
updateUI();
}, 800);
}
});
return {
reset() {
state = 'idle';
updateUI();
return this;
}
};
}
// 使用
const btn = document.querySelector('#my-btn');
const ctrl = createToggleableButton(btn);
</code>
注意边界与可测试性
闭包状态机虽简洁,但要注意:状态不可序列化、难以调试、单元测试需依赖返回对象的 API。建议做到以下几点:
- 所有状态变更必须通过明确定义的 dispatch 或 action 方法,禁止直接修改闭包变量
- 导出当前状态的只读快照(如 getState()),方便日志和断言
- 关键状态变化可触发自定义事件(new CustomEvent),便于外部监听解耦
- 若状态逻辑复杂,考虑用有限状态机库(如 XState)替代手写,但闭包方案仍适合简单、内聚的组件级状态
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











