Skip to content

Instantly share code, notes, and snippets.

@millermedeiros
Created September 2, 2011 17:29
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save millermedeiros/1189235 to your computer and use it in GitHub Desktop.
Save millermedeiros/1189235 to your computer and use it in GitHub Desktop.
Explain difference between revealing module pattern and using a constructor as namespace
//create our "FOO" namespace
window.FOO = window.FOO || {};
FOO.app1 = {
bar : 'foo',
init : function(){
//this wont work as expected since timeout changes scope
// the same would happen if it was an event handler like
// "onclick", "onload", etc..
setTimeout(this.logBar, 15);
},
logBar : function(){
console.log('app1: '+ this.bar);
}
};
FOO.app1.init();
// I've seen some people using this pattern in a couple places
// It has the same output as using a literal object (since "new function"
// returns a new object).
FOO.app2 = new function() {
this.bar = 'foo';
this.init = function() {
//this wont work as expected since timeout changes scope
// the same would happen if it was an event handler like
// "onclick", "onload", etc..
setTimeout(this.logBar, 15);
};
this.logBar = function(){
console.log('app2: '+ this.bar);
};
}
FOO.app2.init();
FOO.app3 = (function() {
//properties that should be exported, we only add stuff to this object if
//it needs to be public and we reference all functions internally as if it
//wasn't part of this object
var app = {
bar : 'foo'
};
function init() {
//work as expected
setTimeout(logBar, 15);
}
function logBar(){
console.log('app3: '+ app.bar);
}
// Export API
// ----------
// we only do it later so we avoid using the "this" keyword or "app.method()"
// through our module code, it helps to reduce scope issues and keeps code
// organized. It's also easier to spot what is public and what isn't.
//
// If we didn't needed to expose "bar" we would just return
// a plain object like:
// {
// init : init,
// logBar : logBar
// }
app.init = init;
app.logBar = logBar;
return app;
}());
FOO.app3.init();
@millermedeiros
Copy link
Author

I just got an e-mail asking the difference about using the revealing module pattern, plain object and new function to create namespaces.

I guess the code explain better than what I could do with words why I usually pick the revealing module pattern and why I only expose the API at the end of the module definition.

It is also related to my other gist: https://gist.github.com/1188835

Only use constructors (new Foo()) when you need to instantiate multiple objects, if it is a static object, use the revealing module pattern or a plain object.

Copy link

ghost commented Sep 2, 2011

I'd like to understand but I need a bit more.
Is there 2 examples above, one w/ new and one w/ module pattern?
Also would this recommendation apply to node, as I see window there.

@millermedeiros
Copy link
Author

on node.js you don't need to worry about global variables or name collision since each module is on a separate file, node.js already have the exports object... On node.js the code would be written as:

exports.bar = 'foo';

function init() {
    //work as expected
    setTimeout(logBar, 15);
}

function logBar(){
    console.log('app4: '+ exports.bar);
}

exports.init = init;
exports.logBar = logBar;

or you could also do like:

var app = {
    bar : 'foo'
};

function init() {
    //work as expected
    setTimeout(logBar, 15);
}

function logBar(){
    console.log('app3: '+ app.bar);
}

app.init = init;
app.logBar = logBar;

//expose API
module.exports = app;

@paullewis
Copy link

Really nice write-up, Miller! :) Turns out

FOO.thingy = new function() {
  // ... my epic wonder code
}

doesn't pass JSHint or JSLint so I've had to stop doing that :(

I'm rather fond of the exporting style, so I might give that a whirl!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment