There are plenty great introductions to Factory Functions, but few describe the details of the pattern. If you don’t know what a Factory Function is, please watch Factory Functions in Javascript or read the transcription.

This article will describe the smaller patterns within the overall Factory Functions Pattern. All code snippets are written in ECMAScript 2015. As of January 2016 these code snippets will require Babel until Node.js has full ECMAScript 2015 support.

The Basics

A Factory Function is just a Function that creates something. It is usually an Object, but it can be anything, a String, an Array, or even another Function. In this article we will focus on Factory Functions as a replacement for ECMAScript 2015 Class.

Here is a simple Factory Function.

// greeter.js

export default () => {

return {

greet() {

console.log('Hello World!');

}

};

}

That just defines the Factory Function but does not create an instance of the object. This is done is another file, typically the main file.

// main.js

import Greeter from './greeter'; const greeter = Greeter(); greeter.greet(); // prints Hello World!

The convention for Factory Functions is to capitalize the name. This way you can think of it like a class but you don’t use new. This is very similar to Scala Case Classes.

Dependency Injection

Let’s say we want to greet to a file or to an API. We will refactor the previous example such that we are not greeting directly to console.log.

// greeter.js

export default (outputStream) => {

return {

greet() {

outputStream.send(‘Hello World!’);

}

};

}

Notice greeter does not need to know how outputStream is implemented.

// main.js

import Greeter from './greeter';

import ConsoleOutputStream from './console-output-stream'; const consoleOutputStream = ConsoleOutputStream();

const greeter = Greeter(consoleOutputStream); greeter.greet(); // prints Hello World!

We inject output stream in the main file. This is Dependency Injection. What is console output stream? It’s just another Factory Function!

// console-output-stream.js

export default () => {

return {

send(line) {

console.log(line);

}

};

}

Unit Testing

Greeter no longer depends on any global references (i.e. console.log), which means we can now unit test it without any dirty tricks.

We want to assert that the output stream was called with “Hello World!”. This is easy to do when we are in full control of the dependencies.

In JavaScript, it is easy to mock objects with an object literal. This technique is use to mock the output stream and pass it into greeter.

Mocha and Chai are the only tools we need.

// test/greeter.js

import { expect } from 'chai';

import Greeter from '../greeter'; describe('greeter', () => {

it('should send a greeting to output stream', () => {

const outputStream = {

send(line) {

expect(line).to.equal('Hello World!');

}

}; const greeter = Greeter(outputStream);

greeter.greet();

});

});

No mocking library required!

Encapsulation

Private data is required for Encapsulation. With ECMAScript 2015 classes, private data is possible, but awkward. Let’s extend our example and make greeter stateful. We will allow others to configure the greeting message, but we will keep the data private.

// greeter.js

export default (outputStream) => {

let _message = 'Hello World!'; return {

greet() {

outputStream.send(_message);

},

set message(message) {

_message = message;

},

get message() {

return _message;

}

};

}

That set/get syntax might look foreign to you, but it is actually just combining ECMAScript 5.1 getters/setters with ECMAScript 2015 Enhanced Object Literals.

We can then use message like a normal property.

// main.js

import Greeter from './greeter';

import ConsoleOutputStream from './console-output-stream'; const consoleOutputStream = ConsoleOutputStream();

const greeter = Greeter(consoleOutputStream); greeter.message = 'Salutations Earth.';

greeter.greet(); // prints Salutations Earth.

It is impossible to access the _message variable from outside of the Factory Function. Data is kept private. Difference instances of greeter will have their own private copy of _message and will not conflict.

Composition

If we keep the objects created using Factory Functions small, we can use composition to create new objects from smaller components. Let’s add some additional functionality so we have something to compose. We will add a wave gesture.

// gesturer.js

export default (outputStream) => {

return {

wave() {

outputStream.send('*Waves hand*');

}

};

}

To create a waving greeter, we simply create the two smaller components, then use Object.assign to compose into a single object.

// main.js

import Greeter from './greeter';

import Gesturer from './gesturer';

import ConsoleOutputStream from './console-output-stream'; const consoleOutputStream = ConsoleOutputStream();

const greeter = Greeter(consoleOutputStream);

const gesturer = Gesturer(consoleOutputStream); const wavingGreeter = Object.assign({}, greeter, gesturer); wavingGreeter.message = 'Salutations Earth.';

wavingGreeter.greet(); // prints Salutations Earth.

wavingGreeter.wave(); // prints *Waves hand*

The waving greeter shares the same state as the components it is made up from. We can set a new message on greeter and waving greeter will use it.

Object.assign assigns properties from left to right. In the example, it assigns greet to the empty object, then wave to an object that contains greet.

If there are conflicts, the right most object wins. Or in other words calling a conflicting method is the same as calling the method on the right most object in the list. You can prevent methods from conflicting by wrapping objects and renaming methods before composing them.

Calling Sibling Methods

In all our previous examples we immediately returned the objects we constructed. In more complex objects we might want a method to call another method on the same object. This is possible, but we need to get a reference to the self.

// head-scratcher.js

export default () => {

const self = {

scratch(location) {

console.log(`scratching ${location}`);

},

confused() {

self.scratch('head');

}

}; return self;

}

Bounded Method References

One of the downsides of ECMAScript 2015 Classes is methods depend on the this reference. Unfortunately if you want to use a class method in function libraries such as Ramda, you will end up having to bind this back to the class instance.

Let’s see what this looks like with ECMAScript 2015 Classes.

// offset.js

export default class Offset {

constructor(delta) {

this.delta = delta;

} add(value) {

return value + this.delta;

}

} // main.js

import Offset from './offset'; const increment = new Offset(1); console.log([1, 2, 3]

.map(increment.add.bind(increment))); // prints [ 2, 3, 4 ]

Objects created using Factory Functions don’t have this problem, since there is no this reference. Let’s see that same example with Factory Functions.

// offset.js

export default (delta) => {

return {

add(value) {

return value + delta;

}

};

} // main.js

import Offset from './offset'; const increment = Offset(1); console.log([1, 2, 3]

.map(increment.add)); // prints [ 2, 3, 4 ]

Notice how much shorter and simpler the code is.

Types

Factory Functions can create informally typed objects. We simply add a getter type property to the object we wish to type.

// duck.js

export default () => {

return {

get type() {

return 'duck';

},

speak() {

return 'quack';

}

};

}

In place of instanceOf, we just use the type property.