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 | var calc = (function initCalc() { |
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 | var calc = (function initCalc() { |
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 | process.nextTick(calc.sub, 2, 3); |
If we want to pass sub
around, we need to bind it to the calc
object
1 | var sub = calc.sub.bind(calc); |
If we do partial application, we must bind calc
too
1 | var subFrom5 = calc.sub.bind(calc, 5); |
2 - Use closure variables
Let us change code slightly to make much friendlier API
1 | var calc = (function initCalc() { |
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 | var subFrom5 = calc.sub.bind(null, 5); |
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 | var calc = new function calcModule() { |