Take the 2-minute tour ×
Code Review Stack Exchange is a question and answer site for peer programmer code reviews. It's 100% free, no registration required.

I am new to JavaScript development, so I'm seeking help in guidelines on how I can better organize my code in a better way. This is what I have for a small app I am working on:

var app = app || {};

app.p = function(){ ... };
app.q = function(){ ... };
app.r = function(){ ... };

app.init = function(){ ... };
app.onload = function(){
    if (window.applicationCache) {
        window.applicationCache.addEventListener('updateready', function() {
            // do stuff
        });
    }
};

window.addEventListener('load', app.onload);
window.addEventListener('online',app.p);

Zepto(function($){
    app.init();
    app.p();

    $('#aaaa').change(function(){
        app.q();
        app.r();
    });

});
  1. Is it good enough that I am splitting my functions and then adding them to a single global object? Any better way?

  2. I am using some native window.addEventListener() calls. Is it ok to keep native code, even when you have a library loaded on the page, just for the performance gain? Or does it depend on the size of codebase? Is it ok for small enough and probably moving in a large one?

  3. How the whole execution begins, like Zepto kickstarts init() function on document ready event and then I take it from there, is this how I should be doing it or is there a better way?

Any other suggestions welcome!

share|improve this question

1 Answer 1

up vote 7 down vote accepted

Namespacing

1) Is it good enough that I am splitting my functions and then adding them to a single global object? Any better way?

Yes, it's a good and popular approach. It's simple and it works.

You might consider using closures to create app.p, app.q and app.r. I think this is referred to as using IIFEs (immediately invoked function expressions) [details]. Right now, app.p, app.q and app.r have no persistent private scope. The only private scope they will have is whatever happens within the function, itself. If they needed to keep track of something, they will need to use a variable in the global scope because it is the only scope outside of the function. Using an 'IIFE' would allow there to be some persistent and private state for each function:

app.p = (function() {
    var someCounter = 0;
    return function(){ 
        someCounter++;
        // do stuff
    }
})();

Now, app.p can access the someCounter variable but nothing else can. Some people don't care for this, but I'm a fan.

For larger projects, the var app = app || {}; might become unwieldy. Something I've been working with a bit that allows a little more flexibility is at the bottom of this page:

http://elegantcode.com/2011/01/26/basic-javascript-part-8-namespaces/

function namespace(namespaceString) {
    var parts = namespaceString.split('.'),
        parent = window,
        currentPart = '';    

    for(var i = 0, length = parts.length; i < length; i++) {
        currentPart = parts[i];
        parent[currentPart] = parent[currentPart] || {};
        parent = parent[currentPart];
    }

    return parent;
}

Using this approach, to define something in a namespace (modified from the same page):

// using an immediately invoked function expression (IIFE)
// keeps things private to the function and prevents spillage
// of variables into this outer scope
(function() {
    // retrieve what exists or make a new definition
    var examples = namespace('io.examples');

    // add something to it (another IIFE)
    examples.log = (function() {
        // can have private variables
        var numMsgs = 0,
            // for this, the api is an invokable function: api(), but
            // we will also add more functions to it: api.subFunction()
            // these will all have access to the numMsgs private variable
            api = function() {
                numMsgs++;
                console.log.apply(console, arguments);
            };
        api.getMsgCount = function() {
            return numMsgs;
        }
        // returning api sets io.examples.log to the api function
        return api;
    })();
})();

And, to use something from a namespace:

// retrieve what exists (we already made something, 
// so it will not create an empty place-holder)
var log = namespace('io.examples.log');

// the api was a function, so we can call it
// or access the sub-function we attached to it
log('hello');
var numSoFar = log.getMsgCount();

A related topic is AMDs (asynchronous module definitions) and dependency-injection (which is rather a sub-set of what AMDs set out to do, I think). Some options are requireJS, yepnope, and angularjs (which entails committing the project to the angularjs framework). I'm sure there are a lot of others, I just don't know them.

native addEventListener

2) I am using some native window.addEventListener() calls...

Historically, when I avoid using a library it's because I don't want to either load it. That being said, the performance difference is impressive. Most things I write are driven from UI events, which are generally rare (how often are you clicking?), and the performance difference between the two doesn't matter. I would say it doesn't even matter if the code base is large. Seems like the main thing would be whether you are handling events that occur super-frequently or not.

It's also worth noting that creating a dependency on a library can hinder the reusability of whatever you're writing.

init process

3) How the whole execution begins, like Zepto kickstarts init() function

If you're using native event listeners, then you don't have a choice, it can't go in the Zepto init. If you're using the Zepto init process, I would just put it in the Zepto(...) if a) nothing else needs a reference to it and b) you don't need it before then, anyway.

share|improve this answer
    
Thanks a lot for your answer, I got to learn a bunch of things I didn't know about :) –  Ashfame Dec 23 '12 at 3:49

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.