VerizonW
VerizonW

Reputation: 1835

Is there any difference between this two JavaScript patterns?

Looking at some JavaScript libraries and other people's code I've seen two common patterns, I don't know if there is a difference or advantage in using one of them. The patterns look sort of like this:

1.

var app = (function () {
    // Private vars

    // Module
    var obj = {
        prop: "",
        method: function () {}
    };

    return obj;
})();

2.

(function () {
    // Private vars

    // Module
    var obj = {
        prop: "",
        method: function () {}
    };

    window.app = obj;
})();

Are this patterns the same or do one of them has an advantage or different use than the other?

Thanks in advance.

Upvotes: 8

Views: 200

Answers (5)

Justin Johnson
Justin Johnson

Reputation: 31300

tl;dr: pick one method and be consistent.


In my opinion, the first method has a slight advantage for readability. In my head, when I read it, I see that, "module app is being defined," and that everything inside of this closure belongs to that module. This is a natural decomposition for me and imposes the object oriented nature of the module about to be defined.

Another reason I favor the first method is that it is cleaner to change the scope into which a module is defined. Every module you define wont need to be part of the global scope. Using the second method, if the scope isn't injected by passing in a parent object as Jared Farrish illustrates with his jQuery example, then you run the risk of breaking your code if you decide to change the name of that parent object. This example illustrates the point:

var namespace = {
  subns: { ... }
};

(function() {
  var module = { ... };
  namespace.subns.someModule = module;
}());

Anytime the identifiers namespace or subns change, you also have to update this module and any other module that follows this pattern and adds itself to the same object.

All in all, neither method one nor method two (with dependency inject) is "better" than the other, it is simply a matter of preference. The only benefit that can come from this discussion is that you should pick one method and be consistent.

Upvotes: 2

Jared Farrish
Jared Farrish

Reputation: 49218

They are both accomplishing the same thing, to create an object in the global namespace at the time the code is run.

One isn't more "hardcoded" than the other, since neither is doing any kind of function prototyping in which you could create clones of the object with the new keyword. It's just a matter of preference, in my opinion.

For instance, jquery does something akin to the latter:

(function( window, undefined ) {

// Use the correct document accordingly with window argument (sandbox)
var document = window.document;
var jQuery = (function() {

// Define a local copy of jQuery
var jQuery = function( selector, context ) {
        // The jQuery object is actually just the init constructor 'enhanced'
        return new jQuery.fn.init( selector, context, rootjQuery );
    },

    // Map over jQuery in case of overwrite
    _jQuery = window.jQuery,

    // Map over the $ in case of overwrite
    _$ = window.$,

...

But Prototype JS Library does the former:

var Prototype = {
  Version: '1.6.1',

  Browser: (function(){
    var ua = navigator.userAgent;
    var isOpera = Object.prototype.toString.call(window.opera) == '[object Opera]';
    return {
      IE:             !!window.attachEvent && !isOpera,
      Opera:          isOpera,
      WebKit:         ua.indexOf('AppleWebKit/') > -1,
      Gecko:          ua.indexOf('Gecko') > -1 && ua.indexOf('KHTML') === -1,
      MobileSafari:   /Apple.*Mobile.*Safari/.test(ua)
    }
  })(),

...

I don't know of any reason why one is better than the other, or that they accomplish their task differently (to create the app object in the window namespace).

Upvotes: 1

jamesmortensen
jamesmortensen

Reputation: 34048

In the first example, if app defined within another function, app will only be available in that local scope, whereas in the second example the app variable is explicitly assigned to the global scope.

In the second example, the app will only be assigned to the global scope if defined in the global scope outside of functions.

Upvotes: 0

Spyder
Spyder

Reputation: 1902

The second form has a slight advantage in that you have a completely self contained function; for example you could then have a standard header and footer for your JS files.

The part I'm not completely sold on is the local variable inside the block. I tend to prefer this:

(function () {
   // Private vars

   // Module
   window.app = {
       prop: "",
       method: function () {}
   };
})();

although that breaks down a bit when you're doing more than one thing, such as building up an object with multiple methods rather than a single object as in this example.

Upvotes: -2

Thilo
Thilo

Reputation: 262724

The second assumes the existence of an object called window in the parent scope and assigns a property there.

The first one leaves it up to the caller to make the assignment, and does not depend on a window being defined (which it probably is only inside of a web browser).

So, I'd say the first one is definitely better (more self-contained, less environment-dependent).

Upvotes: 5

Related Questions