1

I usually use in my code the anonymous function approach:

    (function($,NS){

    window[NS] = $.extend((window[NS] || {}), {

        global : 31,

        init : function(){
            var $d = $(document);

            $.on('click', 'a', $.proxy(this.clickHandler, this));
        },

        clickHandler : function(e){
            console.log('etc');
        }

    });

}(jQuery, "AAABBBCCC"));

However, I recently stumbled upon a much simpler way of adding the given namespace to the window object and protecting the global namespace:

var AAABBBCCC = window.AAABBBCCC || {

    global : 31,

    init : function(){
        var $d = $(document);

        $.on('click', 'a', $.proxy(this.clickHandler, this));
    },

    clickHandler : function(e){
        console.log('etc');
    }

};

I tested both approaches and it looks like both of them are adding to the window object the AAABBBCCC object. I can't notice a difference.

Can you please explain to me what's the difference between these two approaches, and possible advantages/disadvantages for each of them?

4

1 回答 1

4

In the first example you're using JavaScript function scope.

For example, what it allows you to do is to redeclare certain variables under different names - e.g., in your code you're declaring jQuery as $ - this way you can be sure that a variable named $ actually is a jQuery object, and not some variable declared by some other library (such as MooTools, Ext.js, etc.). So the first advantage of an explicit function scope is avoidance of variable names conflicts.

But there's more: in the first case you can declare "private" variables that can be seen only in the context of your "namespace" function. E.g. consider this example:

(function ($) {
    var jQuery = 'hello world';
    var privateVar = 42;
    console.log(jQuery); // hello  world
    console.log($); // jQuery object
})(jQuery);

console.log(jQuery); // jQuery object

The first console.log call would output 'hello world' string, while the second and the last one would output an original jQuery object; so, basically, as you can see, you can use any names you'd like in your isolated scope while not messing with globals.

And consider second variable that you declare in an isolated function: privateVar - if you'll try to get its value from outside the scope of the function, you'll get an undefined result - because that variable exists only in the context of your private "namespace".

Now try the same example without a wrapper function:

jQuery.find('body').css('background', 'blue');

var jQuery = 'hello world';
console.log(jQuery); // hello world

jQuery.find('body').css('background', 'red'); // an error occurred here

Here, while the first call to jQuery would change the page body's background to blue, the second would indeed throw out an error - and all subsequent calls to jQuery wouldn't work, just because you've overwritten the global jQuery variable with your new value (in this case - "hello world" string).

Please refer to this question for further details on scoping in JavaScript: What is the scope of variables in JavaScript?

To conclude: if you don't need private "namespace" variables and redefinition of global names (such as jQuery to $), you can stick to a second, more straightforward way of namespacing.

But it's almost always better to isolate your internal state, so I'd recommend to go for function scopes as a general case.

于 2015-02-20T21:12:09.890 回答