The Static Module Instance wRapper Factory (SMIRF) pattern

Earlier in the year, I wrote about memory waste issues in Caveats of the JS Module Pattern. I’d like to offer a new pattern as a solution to those issues.

First, a reminder of why we like the module pattern: it provides an elegant way to have private methods and variables. For most singleton objects, there is no better option. I’ll use Christian Heilmann’s Revealing Module pattern for my examples:

var currencyExchange = function(){
  var currencies = {
    usd: 1,//always 1, base currency
    gbp: 0.631552356,
    aud: 0.99980004,
    cad: 1.0072999
  };
  var convert = function(fromCurrency, toCurrency, amount){
    var amountInUsd = (fromCurrency === 'usd') ?
      amount : amount / currencies[fromCurrency];
    return (toCurrency === 'usd') ?
      amountInUsd : amountInUsd * currencies[toCurrency];
  };
  var changeRate = function(currency, rate){
    currencies[currency] = rate;
  };
  return {
    convert: convert,
    changeRate: changeRate
  };
}();

The memory waste problem occurs when you use this pattern to create object instances:

var employeeFactory = function(name, salary){
  var giveRaise = function(percent){
    salary = salary * (1 + (percent/100));
    return salary;
  };
  var fire = function(){
    //long, drawn out legal process that takes 5000 lines
  };
  return {
    giveRaise: giveRaise,
    fire: fire
  };
};
var employee1 = employeeFactory('Bob', 30000);
var employee2 = employeeFactory('Mary', 21000);

We now have created two identical but separate versions of the giveRaise and fire functions, wasting CPU in generating the duplicates, and memory in storing them.


SMIRF it down to size

Looking at the singleton example, the elegance of it is that the functions are created once as the script is first run. The reason we can’t easily do that with instantiation is that the functions need to be declared in the scope of the state variables (name and salary) that they’re operating on.

The SMIRF pattern provides a way to have the outer, static module which provides methods shared across all instance objects, avoiding most of the CPU and memory waste.

We still need to create tiny, one line “wrapper” methods for each method on an instance, but the footprint of these is minimal in comparison to that of reproducing large methods for each instance.

var employeeFactory = function(){
  /* These are STATIC functions to hold the majority of code.
   * They should be run in the context of the instance via "call",
   * and the first arg should always be iVars.
   * The "this" keyword and iVars are the only ties these methods
   * have to the object!
   */
  var giveRaise = function(iVars, percent){
    iVars.salary = iVars.salary * (1 + (percent/100));
    return iVars.salary;
  };
  var fire = function(iVars){
    //long, drawn out legal process that takes 5000 lines
  };
  return function(name, salary){
    //This is essentially a constructor function
    var iVars = {
      //Instance variables. All state info should be stored here
      name: name,
      salary: salary
    };
    var instance = {
      //This will be our actual instance object.
      //Fns here are thin wrappers for memory efficiency
      giveRaise: function(percent){
        return giveRaise.call(instance, iVars, percent);
      },
      fire: function(){
        return fire.call(instance, iVars);
      }
    };
    return instance;
  };
}();
var employee1 = employeeFactory('Bob', 30000);
var employee2 = employeeFactory('Mary', 21000);

Note that the methods on the instance object will never vary much from what you see above. They simply run the static methods in the context of the instance, passing the instance variables, and pass back the returned value.

All private variables should be stored in iVars, so that the static method signature is always the same. Publicly accessible variables, of course, would simply be on the instance object itself, accessible via the “this” keyword in the shared static methods.