javascript闭包的特性可以让函数保存自身作用域内的变量,这些变量不会被外部直接访问和修改,非常适合用来封装状态机的内部状态和转移逻辑,避免状态被意外篡改。

闭包与状态机基础概念
什么是javascript闭包
闭包是指有权访问另一个函数作用域中变量的函数,当函数执行完毕后,其执行上下文的作用域链不会被销毁,内部函数依然可以访问外部函数的变量。比如下面的简单示例:
function createCounter() {
let count = 0; // 外部函数变量,被闭包保存
return function() {
count++;
return count;
};
}
const counter = createCounter();
console.log(counter()); // 输出1
console.log(counter()); // 输出2
这里的内部函数就形成了闭包,count变量被持续保存,每次调用counter都会修改并返回最新的count值。
什么是状态机
状态机全称有限状态机,由有限个状态、初始状态、状态转移规则和每个状态下的行为组成。它同一时间只能处于一个状态,接收到特定触发条件后会切换到另一个状态,同时执行对应状态的逻辑。常见的比如订单状态流转,从待支付到已支付再到已发货,就是典型的状态机场景。
用闭包实现状态机的核心思路
用闭包实现状态机可以把状态机的所有内部细节都封装在闭包内部,外部只能通过暴露的方法操作状态,核心思路分为三步:
- 在闭包内部定义状态变量,存储当前状态,外部无法直接修改
- 定义状态转移规则,明确每个状态下可以接收的触发事件,以及事件对应的下一个状态和要执行的行为
- 暴露状态切换方法,外部通过调用该方法传入触发事件,闭包内部根据规则完成状态转移和逻辑执行
完整实现示例
下面以一个简单的灯光状态机为例,灯光有三个状态:关闭、低亮、高亮,触发事件是按下开关,按一次切换一个状态,循环流转。
// 状态机工厂函数,接收初始状态和状态配置
function createLightStateMachine(initState, stateConfig) {
let currentState = initState; // 闭包保存当前状态,外部不可直接访问
// 返回状态机操作对象
return {
// 触发事件,切换状态
trigger(event) {
const stateRule = stateConfig[currentState];
if (!stateRule) {
throw new Error(`当前状态${currentState}没有配置规则`);
}
const nextState = stateRule.transitions[event];
if (!nextState) {
throw new Error(`当前状态${currentState}不支持事件${event}`);
}
// 执行当前状态的退出行为
if (typeof stateRule.onExit === 'function') {
stateRule.onExit();
}
// 切换到下一个状态
currentState = nextState;
// 执行下一个状态的进入行为
const nextStateRule = stateConfig[currentState];
if (typeof nextStateRule.onEnter === 'function') {
nextStateRule.onEnter();
}
return currentState;
},
// 获取当前状态
getState() {
return currentState;
}
};
}
// 定义灯光状态配置
const lightStateConfig = {
'关闭': {
transitions: {
'按开关': '低亮'
},
onExit() {
console.log('灯光关闭状态退出');
},
onEnter() {
console.log('灯光已关闭,亮度0%');
}
},
'低亮': {
transitions: {
'按开关': '高亮'
},
onExit() {
console.log('灯光低亮状态退出');
},
onEnter() {
console.log('灯光低亮,亮度50%');
}
},
'高亮': {
transitions: {
'按开关': '关闭'
},
onExit() {
console.log('灯光高亮状态退出');
},
onEnter() {
console.log('灯光高亮,亮度100%');
}
}
};
// 创建灯光状态机实例
const lightMachine = createLightStateMachine('关闭', lightStateConfig);
// 测试状态切换
console.log(lightMachine.getState()); // 输出 关闭
lightMachine.trigger('按开关'); // 输出 灯光关闭状态退出 灯光低亮,亮度50%
console.log(lightMachine.getState()); // 输出 低亮
lightMachine.trigger('按开关'); // 输出 灯光低亮状态退出 灯光高亮,亮度100%
console.log(lightMachine.getState()); // 输出 高亮
lightMachine.trigger('按开关'); // 输出 灯光高亮状态退出 灯光已关闭,亮度0%
console.log(lightMachine.getState()); // 输出 关闭
实现优势与注意事项
用闭包实现状态机的优势非常明显,首先是封装性好,内部状态和规则都被闭包保护,外部无法直接修改currentState,只能通过暴露的trigger和getState方法操作,避免状态混乱。其次是无额外依赖,不需要引入第三方状态管理库,代码轻量,适合简单场景的状态管理。
需要注意的点是,如果状态机的状态非常多,状态配置会变得冗长,这时候可以考虑把状态配置抽成独立文件维护。另外闭包保存的变量会一直存在内存中,如果状态机实例不再使用,需要及时解除引用,避免内存泄漏。
适用场景
这种实现方式适合状态数量不多、逻辑相对简单的场景,比如前端的按钮交互状态、表单步骤流转、简单的游戏角色状态控制,还有后端的简单业务流程状态管理等。如果状态逻辑非常复杂,也可以基于这个思路扩展,加入状态历史记录、异步状态转移等能力。
javascript闭包状态机函数式编程修改时间:2026-07-12 12:42:26