用构造函数实现轻量级状态机,核心是封装状态、当前状态管理、状态转移逻辑和事件响应,不依赖外部库,保持简洁可控。

定义构造函数与初始状态
构造函数接收初始状态和可选的配置(如状态映射、默认行为),内部用 this.state 保存当前状态,并提供 getState() 方法安全读取:
function StateMachine(initialState, config = {}) {
this.state = initialState;
this.config = config;
this.handlers = config.handlers || {};
}
StateMachine.prototype.getState = function() {
return this.state;
};
添加状态转移方法(transition)
transition 是核心方法:校验目标状态是否合法、触发退出/进入钩子、更新状态。支持传入载荷(payload)供处理逻辑使用:
StateMachine.prototype.transition = function(targetState, payload) {
const from = this.state;
const to = targetState;
// 可选:校验是否允许该转移(例如查表或回调)
if (this.config.canTransition && !this.config.canTransition(from, to)) {
return false;
}
// 执行离开当前状态的回调
if (typeof this.handlers[`onExit${from}`] === 'function') {
this.handlers[`onExit${from}`](payload);
}
// 更新状态
this.state = to;
// 执行进入目标状态的回调
if (typeof this.handlers[`onEnter${to}`] === 'function') {
this.handlers[`onEnter${to}`](payload);
}
// 触发通用状态变更事件
if (typeof this.handlers.onStateChange === 'function') {
this.handlers.onStateChange({ from, to, payload });
}
return true;
};
支持事件驱动的简单动作绑定
通过 on 方法注册事件响应,让状态机对业务动作(如 'click', 'fetchSuccess')做出反应,内部自动映射到对应转移:
StateMachine.prototype.on = function(event, handler) {
this.handlers[event] = handler;
};
StateMachine.prototype.emit = function(event, payload) {
const handler = this.handlers[event];
if (typeof handler === 'function') {
const result = handler.call(this, payload);
// 若 handler 返回字符串,视为目标状态,自动 transition
if (typeof result === 'string') {
this.transition(result, payload);
}
}
};
用法示例:
const machine = new StateMachine('idle', {
handlers: {
onClick() { return 'loading'; },
onLoadSuccess() { return 'success'; },
onLoadError() { return 'error'; }
}
});
machine.emit('onClick'); // → 状态变为 'loading'
machine.emit('onLoadSuccess'); // → 状态变为 'success'
可选增强:只读状态快照与调试支持
添加 dump() 方便调试,返回当前状态和元信息;用 Object.freeze(this)(谨慎使用)或私有属性约定防止意外修改:
StateMachine.prototype.dump = function() {
return {
state: this.state,
timestamp: Date.now()
};
};
// 使用示例
console.log(machine.dump()); // { state: 'success', timestamp: 171... }
不复杂但容易忽略细节:状态名建议用字符串常量统一管理,转移逻辑避免副作用,关键路径做状态合法性断言(如 if (!['idle','loading','success'].includes(to)) throw...)。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











