Factory Functions in JavaScript

Josh Miller

As we move from an age of jQuery plugins and script drop-ins to a world of CommonJS and modular architectures it's becoming increasingly more important to manage JavaScript wisely. One of the features currently missing from JavaScript is the ability to create classes, although that will soon change with ES6. There are multiple methods and patterns to try and recreate this functionality. One of those patterns is Factory Functions.

When you need to add functionality to an existing object, factory functions allow you to add it with ease and very little refactoring. Take a look at the code example below of a factory function.

// Function factory
function Car () {
  var self = {
    make: 'Honda',
    model: 'Accord',
    color: '#cc0000',
    paint: function(color){
      self.color = color;
    }
  };
  return self;
}
 
var myCar = Car();

As you can see, factory functions aren't all that different from other methods of building modular JavaScript.

Simple Syntax

Not only will using factory functions help you in the long run but they are also very simple to code initially. When creating a constructor function you must use 'new' to make sure it instantiates a new object. 'new' allows us to be able to use the 'this' variable inside of our constructor. 'this' allows us to apply properties, methods, and events to our new instantiated object. Using the constructor method is also very rigid in terms of structure. You have to follow the rules in order to properly return and instantiate an object.

However, with factory functions the syntax is much simpler. No need to call ‘new’ in front of your constructor, you can simply call the function and attach it to a variable:

var myCar = Car();

You also have more access to the 'this' variable in factory functions. In factory functions ‘this’ refers to the parent object, so in the function myCar.paint(), ‘this’ refers to ‘myCar’. While in constructor functions ‘this’ refers to the method and not the parent object.

Hello Private/Public functions

When using the function factory architecture you have flexibility in how you build your object. Factory functions allow you to define private variables and methods inside of the instantiation function. In the example below, the ‘Car’ function has a private method of year() and a private variable of location. Both this method and the variable are not accessible from outside the car function.

function Car () {
  // private variable
  var location = 'Denver';
  function year() {
    self.year = new Date().getFullYear();
  }
 
  var self = {
    make: 'Honda',
    model: 'Accord',
    color: '#cc0000',
    paint: function(color){
      self.color = color;
    }
  };
 
  if (!self.year){
    year();
  }
 
  return self;
}
 
var myCar = Car();

Since the year method is private, the following will NOT work:

var myCar = Car();
myCar.year();

Your console will show an error of an undefined function. If you wanted to run the year() function outside of the initial ‘Car’ initialization you would have to add the year() method in the self object. Like this:

function Car () {
  var self = {
    make: 'Honda',
    model: 'Accord',
    color: '#cc0000',
    paint: function(color){
      self.color = color;
    },
    year: function(){
      return self.year = new Date().getFullYear();
    }
  };
 
  return self;
}
 
var myCar = Car();
myCar.year();

Dynamic Objects

This also brings up the fact that factory functions are very dynamic. Since we can have public/private functions we can use if/else statements to easily manipulate our object structure. This gives ultimate flexibility to allow the root function ambiguity and allow parameters to determine what the object returned should be. For example, if you wanted to add specific development methods to your object based on an environment variable you could easily pass the factory function a parameter and adjust the object accordingly.

function Address (param) {
  var self = {};
 
  if (param === 'dev'){
    self = {
      state: ‘Colorado’,
      saveToLog: function(){
        // write info to a log file
      }
    };
  } else {
    self = {
      state: 'Colorado'
    };
  }
 
  return self;
}
 
var devAddress = Address('dev');
var productionAddress = Address();

You can see in the example above that we can allow the object to fit the needs of parameters. In our development environment we add a method that can save information to a log file, whereas, our production version can be without this method and also be lighter in memory. This gives us a more granular way of controlling our object.

Overall, factory functions are very future-proof, flexible and dynamic. Using them to write our JavaScript will allow for a more controlled architecture that can be easily maintained throughout the life of a project.