When I got to the module pattern (your state now?)
Back then I made heavy use of jQuery and could not even tell you how to select a dom element with native JavaScript means. It was worse actually. I knew what code I had to write in order to make jQuery do what I wanted to but I was not aware of why it does what it does. One symptom of this unawareness was that I never was able to remember when I should write down which closing bracket.
If you are in a similar position at the moment (if not, skip to the next heading), it will help to understand how jQuery does its thing. For instance:
$("#someId").click(function(){ console.log("click works"); });
How many functions are there? At least three:
1)
$()2) click()
3) function(){}
In 1) the dollar sign is just an ordinary character such as a,b or c and has no special meaning such as in PHP. It may as well be called jQuery().
1) returns an object which has the function click as property. It may look like this:
function $("#someId")
{
var elemet = create("someId");
elemet.click = function(parameter) {...}
return element;
}
When you type in your function(){console.log(...)}, i.e. 3), into to 2) notice that it becomes a parameter for click. That means in jQuery the definition for the click function may look something like this
(...)
click: function(_callback) {
//do some fancy jQuery stuff
_callback(); //== function(){ console.log("click works");
},
(...)
It is really helpful to realize that you feed your function to the jQuery click function which gets called by the jQuery function. In other words functions can be function parameters for other functions and can be called through the parameter.
The underlying "thing" that makes understanding modules difficult
By "thing" I mean anonymous functions or
(function () {
// ... all vars and functions are in this scope only
// still maintains access to all globals
}());
(Cherry, 2010)
The code snippet makes the browser call function(){} at once and keeps everything in it isolated from the rest of your code. The construct of an anonymous function looks like this:
(()) // minus the function(){}
Notice that there are other ways of achieving the same result (see also https://stackoverflow.com/questions/8774425/vs-in-javascript-closures). Such as
()()
Unfortunately, I do not know a better way to understand this other than to memorise it. That is just what the browser reads as an anonymous function.
It really helps to analyse what is going on there. I found the ()() way easiest for illustration. Foster (2013) walks through it backwards. Take your "regular" JavaScript function.
function hello() {
alert("Hello");
}
Calling hello() alerts "Hello". Putting it into an anonymous function gives:
(function hello() {
alert("Hello");
})()
or
(function hello() {
alert("Hello");
} ())
Since hello() is called immediately, you can actually omit the "hello":
(function () { alert("Hello"); })()
or
(function () { alert("Hello"); }())
See, using an anonymous function is simply wrapping your ordinary function. Another variation might help:
var someOrdinaryFunction = function(_parameter) { alert("Hello"); };
(someOrdinaryFunction)();
or
(someOrdinaryFunction())
Since practically both do the same thing, I would say use the one that makes most sense to you.
The Javascript module pattern
The module pattern just varies what you do with your anonymous functions. I am going to stick with ()() in the following.
Say you want to alert something custom. That works too with anonymous functions: ()(_parameter).
(function(_text) {
alert(_text);
})("my parameter")
This is called global import. You put in that what you want to import in the last pair of brackets and make it available as a parameter of your function.
What happens if your function returns something? If you put the following in your browser's console it will print out "hello":
(function () {
return "Hello";
})()
If you do that...
var test = (function () {
return "Hello";
})()
...test will contain "Hello". This is called export. It is probably more useful to export an object such as:
var test = (function () {
var returnStuff = {
getGreeting: function(){alert("Hello")}
};
return returnStuff;
})();
test.getGreeting(); //Hello
If you put importing and exporting together you know already how to augment (add new methods) modules. This even works across files for the same module.
//file1.js: your base module
var test = (function () {
var returnStuff = {
getGreeting: function(){alert("Hello");}
};
return returnStuff;
})();
//file2.js: augmenting the base module
var test = (function(theModule) {
theModule.getInsult = function() {alert("F'off")};
return theModule;
})(test);
test.getGreeting(); //Hello
test.getInsult(); //F'off
I think that is it. That should give you some pointers and hopefully better understand Cherry's post. To be fair though what helped me most back in the day to make sense of it all was to try the code myself and see what happens when changing stuff.
References
Cherry, 2010: http://www.adequatelygood.com/JavaScript-Module-Pattern-In-Depth.htmlFoster, 2013: http://stackoverflow.com/a/16032906
No comments:
Post a Comment
Chosse "anonymous" if you don't have a login.