Seeking explanation of structure (Revealing Module Pattern) - javascript

RE: The Odin Project: Missile Command canvas game exercise.
This project has very few submissions (it's either very new or very difficult), and the two submissions available for reference are from people possessing more experience than I. In the more accessible submission is the following:
var missileCommand = (function() {
//---------
//hundreds of lines of game logic
//including 'initialize' and 'setupListeners' methods
//---------
return {
initialize: initialize,
setupListeners: setupListeners
};
})();
$( document ).ready( function() {
missileCommand.initialize();
missileCommand.setupListeners();
});
What is the purpose/meaning/structure behind the return and the subsequent method calls within the $(function)? I'm not sure what's going on, save that removing either set breaks everything.
I know the title isn't very descriptive, but I don't have enough information to do much about it. Will edit when I know what to call it.

There's two completely separate patterns here.
var missileCommand = (function() {
//---------
//hundreds of lines of game logic
//including 'initialize' and 'setupListeners' methods
//---------
return {
initialize: initialize,
setupListeners: setupListeners
};
})();
This is an implementation of the revealing module pattern. It allows you to create a module (missileCommand) which exposes a number of public methods (here, initialize, and setupListeners). It also allows you to define and store private methods and variables; which will be defined within the area you've commented.
$( document ).ready( function() {
missileCommand.initialize();
missileCommand.setupListeners();
});
This is a jQuery ready block. When the DOMContentLoaded event has fired, jQuery will run the function provided. Here, that function calls missileCommand.initialize(), then missileCommand.setupListeners().
More often, you'll see the ready block used to attach event handlers to elements;
$(document).ready(function () {
$('#some-selector').on('click', function () {
alert('Hello');
});
});
Note that both of my explanations are a rather short introduction to each subject. Both links (and further Google-ing of the terms), will give you much more detailed explanations.

$ is a jQuery object. What it does here is it binds an anonymous function (containing the two function calls, initialize() and setupListeners()) to the event "ready", which is fired when the document (DOM) is fully loaded.
you can translate that in jQueryFind(myElement).whenCompletelyLoaded(myFunctionToExecuteOnEvent()) (this is not functional code)
The return statement within the missileCommand function makes sure than when you do var myCommands = missileCommand() it returns an object containing both the values of the initialize function and the setupListeners function.

In those 100's of lines of code you would for sure find 2 function declarations matching: function initialize(){} and function setupListeners().
The object returned simply exposes those 2 functions by returning them to allow calling them as:
missileCommand.initialize();
missileCommand.setupListeners();
The properties of the returned object could have different names but author wanted the properties to match the function names....the values of the properties are simply references to the function object declared previously

Related

Javascript Library Quickstart

I'm trying to build a Javascript library that will provide some functionality for a JQuery Plugin I'm putting together.
I got the following skeleton code from searching online although I'm not quite sure how it all works (I do know it's a closure). I've added my functions via declarations.
(function(window, document, $) {
function func_1(){
return 1;
}
function func_2(){
return 2;
}
})(window, document, jQuery);
So I put the above code in a separate JS file and then source it in my HTML page, then I run try to run the function like so (Note: I have JQuery set up as well):
<script type="text/javascript">
$(document).ready(function() {
console.log(func_1());
});
</script>
However, I seem to be getting some errors in Firebug (ReferenceError: func_1 is not defined).
I have two questions:
How do I call my functions?!
I'd like to be able to call the functions in the following format: className.functionName(). How do I restructure the skeleton code to enable me do this and, say, call my function like this: Device.func_1()?
Thanks for your anticipated assistance.
The closure is used to hide internal functions from the rest of the code. You need to explicitly expose the public functions of the library:
var Device = (function(window, document, $) {
function func_1(){
return 1;
}
function func_2(){
return 2;
}
var internalDevice = {
func_1: func_1,
func_2: func_2
};
return internalDevice; // expose functionality to the rest of the code
})(window, document, jQuery);
The (function(window, document, $) {})(window, document, jQuery); part is called an immediately invoked function expression (IIFE). It's used to avoid leaking all the library functions into the global scope. Otherwise, if some other library had a func_1 function it would either be overwritten or overwrite your library's func_1.
The arguments to the function are used to control how the library can affect other parts of the code and relies on it. For example, someone might overwrite the window.$ library so that $ is no longer available everywhere in the code. But since you have a local reference in the closure you can still access it.
Alternatively to using the code above - returning an object - you could also assign your library directly to the global scope:
(function(window, document, $) {
...
window.Device = internalDevice; // expose functionality to the rest of the code
})(window, document, jQuery);
I can only answer question number two, but you can create that by doing this:
var Device = {
function func_1()
{
// your first function
},
function func_2()
{
// your second function
}
};
That way you can just call:
Device.func_1();
Hop that helps :)
When something is inside a closure the scope of it is changed to that closure. func_1 and func_2 can only be seen inside the anonymous function calling them and below.

start javascript code with $(function, etc

I am studying Backbone and the todo example apps from http://todomvc.com/
I have noticed there are 3 severals ways of starting the code in the files:
$(function() {
// code here
});
$(function( $ ) {
// code here
});
(function() {
// code here
}());
I do not understand the differences and when I should use one over the other.
I also saw some people using this to start their code:
$(document).ready(function(){
// code here
});
From what I have seen, this is the full way of writing it right?
In a more general way, should I always include my javascript code into something like that in each files?
Thanks for your advice.
$(document).ready(function(){}) ensures that your code runs on DOM ready, so that you have access to the DOM. You can read more about this in jQuery's documentation.
$(function(){}) is just an alias to #1. Any code in here will wait for DOM ready (see the docs).
$(function($){}) is equivalent to #1 and #2, only you get a clean reference to jQuery in the local scope (see the note below). You can likewise pass in $ to the function in #1, and it'll do the same thing (create a local reference to jQuery).
(function(){}()) is just a self-executing-anonymous-function, used to create a new closure.
Please note that none of these are specific to Backbone. The first 3 are specific to jQuery, while #4 is just vanilla JavaScript.
Note: To understand what's going on in #3 above, remember that $ is an alias to jQuery. However, jQuery is not the only library that uses the $ variable. Since the $ might be overwritten by someone else, you want to ensure that within your scope, $ will always reference jQuery - hence the $ argument.
In the end, it basically boils down to the following 2 options:
If your JavaScript is loaded in the head, you have to wait for document ready, so use this:
jQuery(function($) {
// Your code goes here.
// Use the $ in peace...
});
If you load your JavaScript at the bottom of your document (before the closing body tag - which you should definitely be doing), then there's no need to wait for document ready (since the DOM is already constructed by the time the parser gets to your script), and a SEAF (A.K.A. IIFE) will suffice:
(function($) {
// Use the $ in peace...
}(jQuery));
P.S. For a good understanding of Closures and Scope, see JS101: A Brief Lesson on Scope.
I guess it makes sense to start out, by realizing that $ = jQuery. The purpose of which down below when reading about namespaces within anonymous functions will make more sense. But in essence, you can use either of them. One would use jQuery() instead of $() if they were using multiple libraries, and wanted the $ to be used by the other one.
$(document).ready(function(){
// Here we have jQuery(document) firing off the ready event
// which executes once the DOM has been created in
// order to ensure that elements you are trying to manipulate exist.
});
​$(function () {
// Short-hand version of $(document).ready(function () { });
});
More information on Document.ready()
Putting the $ within the parenthesis ensures the jQuery $ alias (you can be safe it always signifies jQuery this way).
$(function ($) { /* code here : $ always means jQuery now */ });
Lastly you have an IIFE (Immidiately-Invoked Function Expression)
- IIFE explanation
(function (myNameSpace, $) {
// This is an anonymous function - it is ran instantly
// Usually used for namespaces / etc
// This creates a scope/wrapper/closure around everything inside of it
}(window.myNameSpace, jQuery));
The $ at the top (with it's matching jQuery on the bottom) signify that the
$ (dollar sign) stands for jQuery within the scope of the namepsace.
This is done to ensure that other libraries do not collide with what the developer
intends/wants the $ to be used with.
(function (myNameSpace, $) {
// Now because of all of this scope/wrapper/closure awesome...
// you can create -INTERNAL- variables (sort of like Private variables from other langs)
// this variable cannot be accessed outside the namespace unless it is returned / exposed
var internalVariable = '123'; // Internal
// Even Internal functions!
function privateFunction () {
console.log('this is private!');
}
// --------------------------------------------------------
// Public -method- of nameSpace exposing a private variable
// Notice we're using the myNameSpace object we exposed at the top/bottom
myNameSpace.nameSpaceMethod = function () {
privateFunction(); // we can call the private function only inside of the namespace
return internalVariable; // now we could get this variable
};
}(window.myNameSpace, jQuery)); // notice these mirror the above arguments in the anon function
More information on anonymous functions
Now if we're outside of the namespace, we can see how these internal/public methods and variables are effected:
// This will come up undefined
alert(internalVariable);
// This will trigger a -method- of the myNameSpace namespace - and alert "123"
// Showcasing how we access a Public method - which itself has access to the internal variable
// and exposes it to us!
alert(myNameSpace.nameSpaceMethod());
​
These two:
$(function() {
// code here
});
$(document).ready(function(){
// code here
});
Are directly equivalent, they are both the way to start some jQuery when the document has loaded. The former is just a shorter version of the latter.
This one:
(function() {
// code here
}());
is just a scoped function with zero parameters, which is immediately called with zero parameters.

Using self-executing anonymous functions inside the revealing module pattern

Just wanted to know if it was a good JavaScript practice.
Let's say I have many Web pages that all call an initialization function "init()", would it be the right thing to use an IIFE inside my pattern to run the function everytime the script is loaded?
var foo = (function() {
var bar = "something";
(function init() {
// Do something crazy that's gonna be the same across all my web pages
// like adding an event listener or something
// ...
document.write('page init...');
}());
function privatePage1() {
// This stuff is gonna be used only in page1.html via foo.privatePage1
document.write('page 1' + bar);
}
function privatePage2() {
// This stuff is gonna be used only in page2.html via foo.privatePage2
document.write('page 2' + bar);
}
return {
privatePage1: privatePage1,
privatePage2: privatePage2
}
}());
This is a pretty subjective area, but here's my take:
When you use the module pattern, you're providing a contained set of functionality to the rest of your code. It's essentially a mini-library.
In general, I wouldn't expect a library to do anything when I load it, other than initialization steps that are entirely internal to the library (e.g. setting up the configuration, instantiating a few necessary objects, etc) - nothing that actually affects the DOM or otherwise significantly alters the environment (which is why I've never been entirely comfortable with libraries like Date.js or Prototype that change the prototypes of basic objects).
There are a couple of reasons for this, but the main one is that I don't want to have to worry about the load order of my libraries/modules, other than simply managing dependencies. Independent modules shouldn't affect each other at all. When you manipulate the DOM in your module at load time, sooner or later you'll realize that another piece of your code is expecting the DOM to be in a certain state at a certain time, and that you now have to care about whether you load your module before or after that time. This is an extra bit of complexity that's essentially hidden in the script tag that loads your module.
The other issue here is portability and adaptability. Maybe you'll want to use your module in another project with another DOM setup. Maybe you'll want to pass a different DOM element or config variable to the init() function on a specific page. If you execute init() automagically, you lose the opportunity for configuration.
So what I generally do is to set the init() method as an attribute of the returned module object:
var foo = (function() {
function init() {
// Do something crazy that's gonna be the same across all my web pages
}
//...
return {
init: init,
// etc
}
}());
and then call it as needed elsewhere in my code:
foo.init();
Yes, this adds an extra line of redundant code to the initialization for all my pages (though this is probably just one other script anyway, so the added weight is all of 11 characters). But it allows me a more fine-grained control over when the module is initialized, and offers a hook for configuration arguments when I (inevitably) determine I need them later.
Is the init() function the same across web pages? If so, this is what I'd do:
var foo = (function()
{
init();
return {};
}());
If not, I don't see a reason to use an IIFE, and would simplify your original code like so:
var foo = (function()
{
/* body of the original IIFE here */
return {};
}());

Calling jQuery document.ready handler with apply method?

Below is the code I am using in a project with some complex dependencies. After I have made sure that all the dependencies have been loaded I fire the onReadyCallback() also given below. I have two questions :
Is it correct to use, anonymousHandler.apply(MyNameSpace), the apply method on an anonymous Handler being called for Document.ready
From what I understand, because I am using the apply method the anonymous function will fire immediately irregardless of document's ready state. Then how can I pass in the context of MyNameSpace to the anonymousHandler so that "this" inside the function refers to MyNameSpace
var onReadyCallback = function(){
jQuery(document).ready(function(){
if(!this.loggedIn()){
return;
}
...Lots of Code referring to MyNameSpace using "this"
}.apply(MyNameSpace));
};
//load the additional files that are needed and fire onReadyCallback
MyNameSpace.Util.loadFiles(defaultJsFiles,function(){
MyNameSpace.Util.require(['My.App','My.Theme','My.DomHandler'], function(){
onReadyCallback.apply(window);
});
});
How about this, using an anonymous function and call?
jQuery(document).ready(function() {
(function() {
// this == MyNamespace
}).call(MyNamespace);
});
Normally, the ready event jQuery function is called like this
$(function() { /* ... */ });
// or
jQuery(function() { /* ... */ });
// or
jQuery(document).ready(function() { /* ... */ });
Bottom line, the function is not given a particular context; the actual context given by jQuery to the function is the HTMLDocument element, regardless of the argument (in the last example, document). Why is this so is another subject.
Generally, each of these functions are called later, after everything has been loaded, but not necessarily. In your case, there is a reference to MyNameSpace before the ready event happens. Even if Javascript is a LALR-type language, and it will find the symbol declared later, this is not a good practice. What if MyNameSpace would be set to something else later on, before jQuery triggers the ready callback functions? Your ready callback would not get that new reference. Unless intentional, the reference should be made inside the ready callback, when everything is.... ready.
Then, inside the ready callback, there are other techniques to assign a context to a function. lonesomeday have pretty much given the correct way to accomplish what you are trying to do.
(function() {
// this == MyNamespace
}).call(MyNamespace);
The above code executes an anonymous function right away, where this == MyNameSpace
note : the difference between apply and call is decribed here
Now, comes the bottom part of the code you provided :
//load the additional files that are needed and fire onReadyCallback
MyNameSpace.Util.loadFiles(defaultJsFiles,function(){
MyNameSpace.Util.require(['My.App','My.Theme','My.DomHandler'], function(){
onReadyCallback.apply(window);
});
});
This is problematic, and unnecessary. Is the function onReadyCallback only needed there, or will it be called several times? If it needs to be called only once, spare the global namespace, and simply do :
//load the additional files that are needed and fire onReadyCallback
MyNameSpace.Util.loadFiles(defaultJsFiles,function(){
MyNameSpace.Util.require(['My.App','My.Theme','My.DomHandler'], function(){
// if everything is done loading, the function will be executed, otherwise
// it's execution will be postponed later
jQuery(function() {
// create our nicely wrapped anonymous function now
(function() {
if(!this.loggedIn()){
return;
}
// ...Lots of Code referring to MyNameSpace using "this"
})(MyNameSpace); // grab our most recent reference of `MyNameSpace`
});
});
});
If you don't like the indentation (it's merely a developer's taste), replace everything in the ready callback with (something like) :
initMyNameSpace.apply(MyNameSpace);
and create your function outside, on the global space :
function initMyNameSpace() {
if(!this.loggedIn()){
return;
}
// ...Lots of Code referring to MyNameSpace using "this"
};
But I would recommand, at least, to put it in the require callback function so it...
...does not pollute the global namespace with a run-once function
...is not accessible from anywhere (keep it private)
...can be found quickly when editing the source code
etc.
note : usually, apply and call are used to avoid repeatedly accessing objects like some.thing.pretty.deep = value; or when one function needs to be applied to many but not all objects, and thus extending the object's prototype is just not a good idea.
This is my opinion anyway, and how I would do things, without any more knowledge of your code or what you are doing.

Javascript scope help

I am relatively new to javascript so please be patient if what i am asking is completely stupid!
I am trying to make a simple module. Inside the module i want to have a config object that holds settings for the module. I am also using jquery. The jquery selectors work only when in a function directly in the main object/module.
I understand that javascript has functional scope so I am suprised that I cannot use the jquery selectors anywhere inside the module.
EDIT:
I want to be able to directly set all of my configs inside the configs object using jquery selectors. This way i keep all the messy stuff inside one place and can then access configs.whatever throughout the rest of the module. At the moment jquery selectors do not work inside the configs module.
var OB = function() {
var configs = {
'mode' : 'test',
'numOfSelects' : $('.mySelect').find('select').length, // This doesnt work
}
var getMode = function() {
return configs.mode;
}
function init() {
alert(configs.numOfSelects); // This alerts 0 until the following line
alert($('.mySelect').find('select').length); // This correctly alerts 2
};
var handlers = {
successHandler : function() {
alert("Success");
},
errorHandler : function() {
alert("error");
}
}
return {
init : init,
getMode : getMode
}
}( );
$(document).ready(function(){
OB.init();
});
It isn't that jQuery isn't in scope — that's that the code isn't executing when you think it is. The variable config is defined when that anonymous function (var OB = function() {}()) is executed. The DOM isn't ready yet, so that DOM traversal doesn't find anything. When you do the DOM traversal in init(), that isn't executed until it's explicitly called inside the $(document).ready() handler, at which point that DOM is set up. That's the difference you're seeing.
OB() needs to be called after the DOM has completely loaded. Hence the answer by Marcelo, which calls OB() in the ready() method.
EDIT: It's funny that my original answer below was incorrect because I didn't notice two little parentheses at the end of the definition of OB, and it turns out that these are the culprit. You define and then immediately invoke OB, which is before the DOM has been fully loaded. Remove those parentheses and make the change I suggest below.
Calling OB() returns an object with init and getMode, but you haven't called OB(), you've only referred to OB. Try this instead:
$(document).ready(function(){
OB().init();
});
Also, I assume you want to later refer to getMode. In particular, you will to get the copy of getMode that has access to the same local scope that your init() call had access to. To achieve this, you will need to store the result of calling OB() for later use:
var ob;
$(document).ready(function(){
ob = OB();
ob.init();
});
function some_other_function() {
... ob.getMode() ...;
}

Categories

Resources