Useful module pattern

Avoid using `this` keyword in the API object revealed from a module.

When writing JavaScript code, I often use module pattern. A function constructs an object to be returned and used by the outside world. This could be immediately invoked function expression, or CommonJs module.

1
2
3
4
5
6
7
8
9
10
var calc = (function initCalc() {
function add(a, b) { return a + b; }
function sub(a, b) { return a - b; }
return {
add: add,
sub: sub
};
}());
console.log(calc.add(2, 3)); // 5
console.log(calc.sub(2, 3)); // -1

Using function expression initCalc helps to keep functions add and sub private and inaccessible to the outside world. We separate individual features (functions add and sub) from constructing the public API (returning an object with add and sub method properties). The module reveals certain API to the world; this is called revealing module pattern. The explicit export can be taken one step further to write portable javascript code using universal module definition.

Let us think about the exported (returned object). It has full access to the variables defined inside the initCalc closure. I always try to follow simple rule to make the API easier to use

Avoid using this in the returned API object whenever possible.

Suppose we decide that subtraction (sub method) should be implemented using addition and decide to reuse the add method. We could go about it in two ways.

1 - Use this keyword

1
2
3
4
5
6
7
8
9
10
11
var calc = (function initCalc() {
function add(a, b) { return a + b; }
return {
add: add,
sub: function (a, b) {
return this.add(a, -b);
}
};
}());
console.log(calc.add(2, 3)); // 5
console.log(calc.sub(2, 3)); // -1

This method has huge shortcoming: the function calc.sub is only valid if the sub method is called in the context of the calc object. In other words, unless we call calc.sub it will not work. Thus we cannot use it as a callback

1
2
3
4
5
process.nextTick(calc.sub, 2, 3);
index.js:19
return this.add(a, -b);
^
TypeError: Object #<Object> has no method 'add'

If we want to pass sub around, we need to bind it to the calc object

1
2
var sub = calc.sub.bind(calc);
process.nextTick(sub, 2, 3); // silent -1

If we do partial application, we must bind calc too

1
2
var subFrom5 = calc.sub.bind(calc, 5);
console.log(subFrom5(4)); // 1

2 - Use closure variables

Let us change code slightly to make much friendlier API

1
2
3
4
5
6
7
8
9
10
var calc = (function initCalc() {
function add(a, b) { return a + b; }
return {
add: add,
// use function add instead of method this.add
sub: function (a, b) {
return add(a, -b);
}
};
}());

Now we can freely pass calc methods around - they no longer need to be bound.

1
process.nextTick(calc.sub, 2, 3); // silent -1

We can do partial application without worrying about the context

1
2
var subFrom5 = calc.sub.bind(null, 5);
console.log(subFrom5(4)); // 1

Conclusion

When constructing the public API object, it pays to think how to make it simpler to use. Using this keyword requires each function to be invoked as a method, or be bound to the API object. Avoiding this and using closure variables directly makes the API just a collection of composable functions - a simple and useful module pattern.

Update - an interesting solution by Peter Downs

Peter Downs @peterldowns showed me an interesting 3rd solution to this problem. He used a functional expression called with new keyword to attach exported methods to this object returned implicitly. See gist

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var calc = new function calcModule() {
// do not use `this` keyword
function add(a, b) { return a + b; };
function sub(a, b) {
return add(a, -b);
};
// attach exported methods
this.add = add;
this.sub = sub;
// this object is returned implicitly
};
console.log(calc.add(2, 3)); // 5
console.log(calc.sub(2, 3)); // -1
var subtract = calc.sub;
// each method works separately
console.log(subtract(2, 4));