Observer/Observable Example in Javascript

by spoike

HTML

<ul class="log">
  <li class="head">
    Log entries
  </li>
</ul>

CSS

ul.log {
  padding: 10px;
  background-color: #efefef;
  font-family: Arial, sans-serif;
}

ul.log li {
  padding: 10px;
  background-color: #fff;
  border-top: dashed black thin;
}

ul.log li.head {
  font-weight: bold;
  border-top: none;
}

JavaScript

var log = function(entry) {
  $log = $('ul.log');
  $log.append('<li>' + entry + '</li>');
};

var observable = function(v) {
  var val = v, subscribers = [];
  
  // the observable object
  var output = {
    
    // subscribes to event
    onChange : function(func) {
      subscribers.push(func);
      return output; // enables chaining
    },
    
    // the method that changes the observable object
    // and emits the event
    set : function(v) {
      var i;
      val = v;
      for (i = 0; i < subscribers.length; i++) {
        // this is hardly fault tolerant but as long 
        // as subscribers are functions it'll work
        subscribers[i](v);
      }
      return output;
    },
    
    get : function() {
      return val;
    },
    
    // the method emits an event with given message,
    // useful when the observable is a complex
    // object
    emit : function(msg) {
      var i;
      for (i = 0; i < subscribers.length; i++) {
        subscribers[i](msg, output);
      }
      return output;
    },
    
    // removes subscription
    off : function(func) {
      // idiomatic JS for removing objects in array
      var index = subscribers.indexOf(func);
      subscribers.splice(index, 1);
      return output;
    }
    
  };
  
  return output;
  
};

// The player token - a space ship
var shipComponent = {
  velocity : observable(0)
};

// Gameloop Subject
var gameLoopComponent = observable(0);

// The Player UI component
var playerUi = (function(ship) {
  var module = {
    setVelocity: function(v) {
      log("Velocity: " + v);
    },
    init: function() {
      log("Initializing UI");
      ship.velocity.onChange(module.setVelocity);
    }
  };
  
  return module;
  
}(shipComponent));

// Velocity randomizer component. It randomizes the velocity.
// Doesn't need to be a module as it only reacts to the game loop
var velocityRandomizer = (function(ship, gameLoop) {

  gameLoop.onChange(function(millis) {
    var r = Math.random() / 10;
  ...