JavaScript与有限状态机学习2014-09-15 阮一峰 有限状态机(Finite-state machine)是一个非常有用的模型,可以模拟世界上大部分事物。简单说,它有三个特征:* 状态总数(state)是有限的。* 任一时刻,只处在一种状态之中。* 某种条件下,会从一种状态转变(transition)到另一种状态。它对JavaScript的意义在于,很多对象可以写成有限状态机。举例来说,网页上有一个菜单元素。鼠标悬停的时候,菜单显示;鼠标移开的时候,菜单隐藏。如果使用有限状态机描述,就是这个菜单只有两种状态(显示和隐藏),鼠标会引发状态转变。代码可以写成下面这样:
var menu = { // 当前状态 currentState: "hide", // 绑定事件 initialize: function() { var self = this; self.on("hover", self.transition); }, // 状态转换 transition: function(event){ switch(this.currentState) { case "hide": this.currentState = "show"; doSomething(); break; case "show": this.currentState = "hide"; doSomething(); break; default: console.log("Invalid State!"); break; } }};可以看到,有限状态机的写法,逻辑清晰,表达力强,有利于封装事件。一个对象的状态越多、发生的事件越多,就越适合采用有限状态机的写法。另外,JavaScript语言是一种异步操作特别多的语言,常用的解决方法是指定回调函数,但这样会造成代码结构混乱、难以测试和除错等问题。有限状态机提供了更好的办法:把异步操作与对象的状态改变挂钩,当异步操作结束的时候,发生相应的状态改变,由此再触发其他操作。这要比回调函数、事件监听、发布/订阅等解决方案,在逻辑上更合理,更易于降低代码的复杂度。下面介绍一个有限状态机的函数库Javascript Finite State Machine。这个库非常好懂,可以帮助我们加深理解,而且功能一点都不弱。该库提供一个全局对象StateMachine,使用该对象的create方法,可以生成有限状态机的实例。var fsm = StateMachine.create();生成的时候,需要提供一个参数对象,用来描述实例的性质。比如,交通信号灯(红绿灯)可以这样描述:
var fsm = StateMachine.create({ initial: "green", events: [ { name: "warn",from: "green",to: "yellow" }, { name: "stop", from: "yellow", to: "red" }, { name: "ready",from: "red",to: "yellow" }, { name: "go", from: "yellow", to: "green" } ]});交通信号灯的初始状态(initial)为green,events属性是触发状态改变的各种事件,比如warn事件使得green状态变成yellow状态,stop事件使得yellow状态变成red状态等等。生成实例以后,就可以随时查询当前状态。* fsm.current :返回当前状态。* fsm.is(s) :返回一个布尔值,表示状态s是否为当前状态。* fsm.can(e) :返回一个布尔值,表示事件e是否能在当前状态触发。* fsm.cannot(e) :返回一个布尔值,表示事件e是否不能在当前状态触发。