In
You Dont Know JS Chapter 5: Scope Closure, there is following code snippet to illustrate the power of module pattern.
var MyModules = (function Manager() {
var modules = {};
function define(name, deps, impl) {
for (var i=0; i<deps.length; i++) {
deps[i] = modules[deps[i]];
}
modules[name] = impl.apply(impl, deps);
console.log("module "+modules[name]);
}
function get(name) {
return modules[name];
}
return {
define: define,
get: get
};
})();
MyModules.define( "bar", [], function(){
function hello(who) {
return "Let me introduce: " + who;
}
return {
hello: hello
};
} );
MyModules.define( "foo", ["bar"], function(bar){
var hungry = "hippo";
function awesome() {
console.log( bar.hello( hungry ).toUpperCase() );
}
return {
awesome: awesome
};
} );
var bar = MyModules.get( "bar" );
var foo = MyModules.get( "foo" );
console.log(bar.hello( "hippo" )); // Let me introduce: hippo
foo.awesome(); // LET ME INTRODUCE: HIPPO
What does this line do?
modules[name] = impl.apply(impl, deps);
It is another way of invoking a function, sort of like Java reflection. And we get to pass an array variable in the second argument to replace a list of parameters. What is the first argument for?
According to https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/apply
fun.apply(thisArg, [argsArray])
Parameters
thisArg
- The value of
this
provided for the call to fun
. Note that this
may not be the actual value seen by the method: if the method is a function in non-strict mode code, null
and undefined
will be replaced with the global object, and primitive values will be boxed.
I don't quite understand this definition. As far as I am concerned,
fun.apply(thisArg, [argsArray]) = thisArg.fun(arg1, arg2....)
In this case, I also don't understand why the first parameter is 'impl'. But I have proved it can be replaced with 'null'.
The next question is why the function needs to be called in such a unconventional way. Could it be called normally?
If we put
modules[name] = impl(deps);
bar.hello() executes OK, but foo.awsome() throws TypeError: bar.hello is not a function.
Then try
modules[name] = impl(deps[0]);
It does work. But obviously it's not a universal solution. Hence the use of apply().