State.js is a JavaScript library for embedding composable, heritable first-class states into arbitrary owner objects.

varstate=require('state');// >>> [Function]

state = require'state'# >>> [Function]

The exported state function will be used here in two ways: (1) to define structures called state expressions, which describe behavior in terms of methods, data, events, etc.; and (2) to implement a composite state expression on an owner, producing a tree of States that belong to the owner and describe its potential exhibited behaviors.

The implementing form has two effects: (1) the owner is given a new state method, which closes over the owner’s new state tree and serves as the accessor to its States; and (2) for any method defined at least once in the state tree, a corresponding dispatcher method is created and added to the owner.

State methods express or override behavior of the owner. Method calls received by the owner are dispatched to its current state’s own or inherited implementation of the corresponding method.

By default, state methods are invoked in the context of the owner, just like normal methods. To gain insight into its place in the owner’s state tree, a method definition can instead be contextually bound to the State for which the method acts. (This will be the State in which the method is defined, unless the method is inherited from a protostate, in which case the context will be the inheriting epistate.)

functionAvenger(name){this.name=name;}Avenger.prototype.greet=function(){return"Hello.";};state(Avenger.prototype,'abstract',{Terse:state('default'),Verbose:state({greet:state.bind(function(){returnthis.superstate.call('greet')+" My name is "+this.owner.name+"...";})})});varinigo=newAvenger('Inigo');inigo.state();// >>> State 'Terse'inigo.greet();// >>> "Hello."inigo.state('-> Verbose');// >>> State 'Verbose'inigo.greet();// >>> "Hello. My name is Inigo..."

State instances are nominally immutable by default. This restriction forces any changes in the owner’s State-based behavior to be expressed in terms of transitions between States.

Alternatively, a State may be explicitly expressed as mutable, such that modular pieces of behavior may be inserted and implemented dynamically into a live State, thereby allowing changes in behavior to be exhibited via mutations as well.

functionActor(){}state(Actor.prototype,'abstract',{Casual:state({greet:function(){return"Hi!";}}),Formal:state('default',{greet:function(){return"How do you do?";}})});

functionContainer(){}Container.prototype=Object.create(View);Container.prototype.constructor=Container;state(Container.prototype,'abstract',{Grid:state('default initial'),List:state,transitions:{GridToList:{origin:'Grid',target:'List',action:function(){// Rearrange subviews into a vertical column// Change states of the subviews, if applicable// Load model data as appropriate for this statethis.end();}},ListToGrid:{origin:'List',target:'Grid',action:function(){// ...this.end();}}}});