Lots of people are doing this nowadays:
(function(window, $, undefined){ // my special module }(window, jQuery)); |
If you’re using this, it’s probably not needed. It’s usually just redundant cruft. The IIFE itself is okay (i.e. (function(){...}())
). It’s the arguments that are the problem.
This strange concoction is used to protect a module’s scope from the environment in which its placed.
I have some bones to pick though…
If you can’t trust the window
variable, then what can you trust? And you’re not even guaranteeing anything by passing it in. Some script could still overwrite it before you arrive. And the window
object is still available for other scripts to mutate as they please, even after your have passed it in.
And you can’t trust jQuery either? You think some prototype.js imp is going to somehow travel into your code and re-assign the global dollar symbol? Ok ok, this may be permissible if you’re creating a third-party jQuery script, but certainly not if you have full control of your app.
Most importantly, who the hell overwrites undefined
? Again, if you’re having to protect against this then you should deal with that issue directly. Go and knock on Bob’s door and tell him to stop overwriting undefined
!
I know, I know. You’re writing a third-party script which may be placed in hostile environments. But here’s the thing: for every potential breach that you’re “protecting” yourself from there are a near-infinite amount of other things that someone could do to mess up your script, and you can’t protect yourself against all of them!
In my opinion, it’s acceptable for your code to be sensitive to the assumptions it makes about its environment. Yes, Bob, my module/plugin/library is going to mess up if you decide to overwrite undefined
, and you should expect it to. Why should we protect ourselves from this imaginary (and probably non-existent) behaviour? I would love to know who overwrites undefined
. Do you? If you do, then stop it.
I’m definitely not having a go at the general pattern of (i.e. the humble IIFE):
(function(){ }()) |
Actually, it’s incredibly useful in places. It allows me to create and run in a fresh scope which means I don’t have to risk polluting the global namespace.
Passing undefined
though… The only possible benefits it gives are: a potential minuscule performance improvement due to a slightly lesser scope lookup (so miniscule that you’d be crazy to care). Also, it provides you with the possibility to use an alias like undef
, but I’m not sure how helpful that really is anyway. And what’s wrong with var undef;
?
Also, for readability’s sake, don’t pass so many things into your module’s main IIFE. It means the reader has to scroll all the way to the bottom just to see what each value is.
So, to sum up, this pattern:
(function(window, $, undefined){ // all ma code }(window, jQuery)); |
… is not the cure people claim it to be.
Thanks for reading! Please share your thoughts with me on Twitter. Have a great day!
Note that there are other reasons to use the IIFE pattern, namely reducing scope lookups and better compression (minification). I thought those were the most important ones…
@Mathias, good point about compression. I forgot about that. But I don’t think that’s how this pattern is usually sold. It’s said to be a way to minimise the hostile global’s effect on your code. FWIW, I think it’s a bad idea to cater to compressors when coding. Obviously we need to make better compressors? Also, surely the scope lookup benefits are, as I mentioned, so tiny that they can’t possibly have a real effect?
My main reason for passing arguments is to help me and future maintainers better understand what the external dependencies of my code are (which means, I don’t generally bother passing in
window
and definitely notundefined
). Given that I also get the benefits that Mathias mentions, seems worthwhile enough (though, again, I agree that it’s close to worthless to do it from a motive of distrusting the built-in globals).Well,
you probably should not use $ at all in the first place, it’s a defacto standard now that jQuery use it, but the variable was never intended to be associated with jQuery in the first place and it’s a bit arrogant (for anyone) to defacto overwrite it in a library as a shorten for something else.
Turn it the other side around, you use prototype, what are the chances you encounter jQuery? Pretty big chances, you have to scope it.
I will say that is you can’t trust undefined your going to have much bigger issues 😛
In our project there is a lot of legacy code, which uses $() as an ID selector, so it is convenient to pass jQuery instance to IIFE and use it as $.
@Brian, I guess that’s ok, and I’ve done the same in some cases. But I’d be wary of integrating the dependency assignments into the IIFE. IMHO it’s clearer to read when dependencies are listed (both name and value) in full at the top of the file. CommonJS/AMD appeals to me in this way.
@Cedric. re: the dollar, I agree. I don’t really buy the mix’n’match jQuery/Prototype argument though. I doubt a seasoned developer or anyone who actually cares about this stuff would even consider having them both on the same page/app.
Passing in jQuery means you can still use the short $ syntax even in a noConflict environment. Both window and undefined will minify a lot better when passed as arguments.
I personally would pass window as ctx, like so:
This makes it a lot easier to pass in a div or something when composing multiple apps into a single page. And it also makes your app a lot easier to port to commonJS or AMD.
I agree that
undefined
is unnecessary for the average plugin. The IIFE itself is incredibly valuable as a defensive tool because there are unfortunately a lot of sites that use multiple versions of jQuery and even Prototype to glue together a mess ‘o code. See the latimes.com home page for an example that loads prototype/scriptaculous and two different versions of jQuery.@Blerik, why not just reference
window
? When willctx
not be the window?@Dave, re: latimes, they only do it because it’s possible to. And we only make it possible because they do it. etc. ad infinitum.
I go a little further:
(function($,window,document,undef) {
//…
}(this.jQuery,this,this.document));
Why this? Because this happens to be window at the global scope. At window happens to contain all global variables. But this removes the depency from the window object, whih could be overwritten as well.
Not only to protect my script against (accidental) overwrites of these important variables, but also because users of my script will blame *ME* when it doesn’t work – and obiously I have no way of knowing why it wouldn’t if I can’t reproduce whatever some other script might be doing.
Better to protect than to repair.
One reason for passing in window is for testing. You can then pass in a mock object in place of window so the global scope doesn’t get polluted with variables between each test.
I use it largely for compression benefits, and when developing things to put into WordPress, where jQuery is automatically in noConflict mode.
@James: When will ctx not be the window? Some examples
– When using node.js, your global context will not be window, unless you load a dom emulation layer. But there is lots of code that doesn’t do anything visual, but still needs a context (to manage namespaces for instance).
– When combining multiple versions of code, you want to pass in something other than window, so the old and the new version won’t clobber each others namespaces. For instance, when you are trying to cleanly separate an old version of an api from a new version, you can wrap the old version of the code in the new api wrapper, and call some old methods through the new api. Wrapping an app that has explicit references to window is possible, but ugly. Passing in the window object explicitly means you can change it a lot easier.
@Joe, Surely it’s best not to sacrifice readability and/or terseness for some marginal compression benefit? I rather write my code in a way that best presents meaning rather than caring about compression. I’m sure most compressors will solve this for you anyway.
@Blerik, But we’re talking about IIFE, as in *immediately-invoked*. How exactly do you pass in something else when combining multiple versions of the code? You’d have to manually change what you pass in at the bottom end of the IIFE, like:
Frankly, I prefer putting this inside the IIFE at the top. Why should the reader have to scroll all the way down to see this information?
Non-immediately-invoked functions that are passed the context are an entirely different matter.
@Martijn, What’s the point in
this.document
? Can’t you just writedocument
?> If you can’t trust the window variable, then what can you trust?
Just imagine you want to be able to use your module either in the browser or in a nodejs env… where you don’t have a `window` object, then you can do something like:
(function(exports) {
exports.foo = function foo(){};
})(window || exports);
@NiKo, in that case, yes, it’s valid. I see the pattern a lot in client-side-only code though.
@James
If you’re encapsulating your code in an IIFE anyway, how much less readable is it to throw window and undefined in just for the sake of compression. Considering EVERYONE’s doing it (which is what you’re complaining about) I don’t think anyone has any misunderstanding of what’s going on when they see that at the top of the code. They shouldn’t need to bother going to the bottom of the code to see what you’re passing in.
Regarding “undefined”: do a lot of people really test code against a variable named “undefined”? Even though I’m sure it works 99.99% of the time, it just seems, well, wrong. Undefined isn’t a value. It’s a type. I learned a long time ago to do:
Ok, a bit verbose, but so’s a ton of stuff in javascript. So put it in your toolbox like you do with anything else, and make a function:
It’s expressive, correct, and doesn’t test your stuff against something that you hope doesn’t exist. It seems odd that anyone who’s concerned enough about such things to create a wrapper like the one we’re discussing, would worry about the definition of “undefined” instead of just not using it.
@James. I agree, that’s quite readable. However, you now have an extra function call whenever you use it. The IIFE undefined seems cleaner, and more performant to me, vs that, without any sacrifice in protection or readability. It’s better than the type of/string comparison we all have learned, as it is more performant, and IMHO more readable. It’s equivalent, again IMHO, to the alternative I had also learned as the “better” version of that typeof check; namely:
void 0 !== foo
yet ‘undefined’ is more readable (at a minor cost of a local scope lookup). And if someone then is at the point where even that tiny cost matters, personally, I think they’re perhaps a bit too far into microoptimization territory. 😀
I’m pretty sure this will throw a
ReferenceError
ifwindow
doesn’t exist:Valid as argument would be something like:
which is so much worse. I agree with James:
It’s such a stupid, hyped thing. Nobody actually thinks about it.
This might throw an exception too btw:
and therefore is definitely not the same as
(I also don’t get the
===
. There’s absolutely no point at all whatsoever. Good minifying even removes a=
because it knows that.)@Rudie – true, they are not exactly the same, and that’s an important distinction. Using a function to test for undefined would throw an exception is testing for the existence of global. For me, most real-world use cases involve testing parameters and properties for existence, though, so it’s not really an issue.
As for == vs ===, it comes from habit. I prefer to write code that, when testing two objects that should be the same data type, uses a comparison operator that requires them to be the same data type.
Since, as you noted, a good compressor will optimize it. That’s one of the reasons we use them. So I prefer to write expressive code without worrying about whether an ‘==’ doesn’t carry a risk in one specific situation, and let the optimizer worry about saving characters. That’s just my style, it’s neither right nor wrong, and it has no effect on performance or size of the compressed code. But developing habits like this helps me write code with fewer bugs, ymmv.
I am new to Javascript. And in my small career I have seen ECMASCRIPT 5. I dont know any way to override undefined with this edition.
So, I ofcourse agree with your points regarding undefined. But I sometimes really need the $ in IIFE.
BTW, I really like your style of writing.
Nice, this article actually solved a problem for me. I’m adding features to an old site with a lot of prototype.js legacy code. Of course, I’ve been running with the compatibility mode. I haven’t even thought about the simple and easy workaround with
That’s actually pretty good.
Nice post.
Good article, makes me reconsider my current practice.
One reason to pass in $, and other dependencies, is to satisfy jshint in strict mode.
Jshint accepts the $ and _ as global variables and won’t complain. This is useful for one object per file at dev time. It’s just one way to let jshint know, you can also use an rc file or comments aimed at jshint directly. So I don’t think this is a conclusive reason to pass them in, just an added bonus.