I guess using this pattern is the new hotness, but I don't understand what the advantage is and I don't understand the scoping implications.
The pattern:
(function(window, document, undefined){
window.MyObject = {
methodA: function() { ... },
methodB: function() { ... }
};
})(window, document)
So I have several questions about this.
Is there a particular advantage to encapsulating an object like this?
Why are window and document being fed in instead of just being accessed normally?
Why the heck is undefined
being passed in?
Is attaching the object we're creating directly to window a particularly good idea?
I'm used to what I'll call the Crockford style of Javascript encapsulation (because I got it off the Douglas Crockford Javascript videos).
NameSpace.MyObject = function() {
// Private methods
// These methods are available in the closure
// but are not exposed outside the object we'll be returning.
var methodA = function() { ... };
// Public methods
// We return an object that uses our private functions,
// but only exposes the interface we want to be available.
return {
methodB: function() {
var a = methodA();
},
methodC: function() { ... }
}
// Note that we're executing the function here.
}();
Is one of these patterns functionally better than the other? Is the first one an evolution of the other?
Why are window and document being fed in instead of just being accessed normally?
Generally to fasten the identifier resolution process, having them as local variables can help (although IMO the performance improvements may be negligible).
Passing the global object is also a widely used technique on non-browser environments, where you don't have a window
identifier at the global scope, e.g.:
(function (global) {
//..
})(this); // this on the global execution context is
// the global object itself
Why the heck is undefined being passed in?
This is made because the undefined
global property in ECMAScript 3, is mutable, meaning that someone could change its value affecting your code, for example:
undefined = true; // mutable
(function (undefined) {
alert(typeof undefined); // "undefined", the local identifier
})(); // <-- no value passed, undefined by default
If you look carefully undefined
is actually not being passed (there's no argument on the function call), that's one of the reliable ways to get the undefined
value, without using the property window.undefined
.
The name undefined
in JavaScript doesn't mean anything special, is not a keyword like true
, false
, etc..., it's just an identifier.
Just for the record, in ECMAScript 5, this property was made non-writable...
Is attaching the object we're creating directly to window a particularly good idea?
It's a common way used to declare global properties when you are on another function scope.
This particular style does bring some benefits over the "Crockford" style. Primarily, passing window
and document
allows the script to be more efficiently minified. A minifier can rename those parameters to single-character names, saving 5 and 7 bytes respectively per reference. This can add up: jQuery references window
33 times and document
91 times. Minifying each token down to one character saves 802 bytes.
Additionally, you do get an execution speed benefit. When I first read @joekarl's assertion that it provides a performance benefit, I thought, "that seems rather spurious." So I profiled the actual performance with a test page. Referencing window
one hundred million times, the local variable reference provides a modest 20% speed increase (4200 ms to 3400ms) in Firefox 3.6 and a shocking 31,000% increase (13 sec to 400ms) in Chrome 9.
Of course, you're never going to reference window
100,000,000 times in practice, and even 10,000 direct references only take 1ms in Chrome, so the actual performance gain here is almost completely negligible.
Why the heck is
undefined
being passed in?
Because (as mentioned by @CMS) the token undefined
is actually undefined. Unlike null
, it has no special meaning, and you're free to assign to this identifier like any other variable name. (Note, however, that this is no longer true in ECMAScript 5.)
Is attaching the object we're creating directly to window a particularly good idea?
The window
object is the global scope, so that's exactly what you're doing at some point, whether or not you explictly write "window." window.Namespace = {};
and Namespace = {};
are equivalent.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With