How does this JavaScript/jQuery syntax work: (function( window, undefined ) { })(window)?
Solution 1
The undefined is a normal variable and can be changed simply with undefined = "new value";
. So jQuery creates a local "undefined" variable that is REALLY undefined.
The window variable is made local for performance reasons. Because when JavaScript looks up a variable, it first goes through the local variables until it finds the variable name. When it's not found, JavaScript goes through the next scope etc. until it filters through the global variables. So if the window variable is made local, JavaScript can look it up quicker. Further information: Speed Up Your JavaScript - Nicholas C. Zakas
Solution 2
Undefined
By declaring undefined
as an argument but never passing a value to it ensures that it is always undefined, as it is simply a variable in the global scope that can be overwritten. This makes a === undefined
a safe alternative to typeof a == 'undefined'
, which saves a few characters. It also makes the code more minifier-friendly, as undefined
can be shortened to u
for example, saving a few more characters.
Window
Passing window
as an argument keeps a copy in the local scope, which affects performance: http://jsperf.com/short-scope. All accesses to window
will now have to travel one level less up the scope chain. As with undefined
, a local copy again allows for more aggressive minification.
Sidenote:
Though this may not have been the intention of the jQuery developers, passing in window
allows the library to be more easily integrated in server-side Javascript environments, for example node.js - where there is no global window
object. In such a situation, only one line needs to be changed to replace the window
object with another one. In the case of jQuery, a mock window
object can be created and passed in for the purpose of HTML scraping (a library such as jsdom can do this).
Solution 3
Others have explained undefined
. undefined
is like a global variable that can be redefined to any value. This technique is to prevent all undefined checks from breaking if someone wrote say, undefined = 10
somewhere. An argument that is never passed is guaranteed to be real undefined
irrespective of the value of the variable undefined
.
The reason to pass window can be illustrated with the following example.
(function() {
console.log(window);
...
...
...
var window = 10;
})();
What does the console log? The value of window
object right? Wrong! 10? Wrong! It logs undefined
. Javascript interpreter (or JIT compiler) rewrites it this way -
(function() {
var window; //and every other var in this function
console.log(window);
...
...
...
window = 10;
})();
However, if you get the window
variable as an argument, there is no var and hence no surprises.
I don't know if jQuery is doing it, but if you are redefining window
local variable anywhere in your function for whatever reason, it is a good idea to borrow it from global scope.
Solution 4
window
is passed in like that just in case someone decides to redefine the window object in IE, I assume the same for undefined
, in case it's re-assigned in some way later.
The top window
in that script is just naming the argument "window", an argument that's more local that the global window
reference and it what the code inside this closure will use. The window
at the end is actually specifying what to pass for the first argument, in this case the current meaning of window
...the hope is you haven't screwed up window
before that happens.
This may be easier to think of by showing the most typical case used in jQuery, plugin .noConflict()
handling, so for the majority of code you can still use $
, even if it means something other than jQuery
outside this scope:
(function($) {
//inside here, $ == jQuery, it was passed as the first argument
})(jQuery);
Solution 5
Tested with 1000000 iterations. This kind of localization had no effect in performance. Not even a single millisecond in 1000000 iterations. This is simply useless.
Related videos on Youtube
dkinzer
Polyglot full-stack web developer interested in robotics and AI. I love vim, lisps, ruby, git and bash. I'm a proponent and practitioner of test assisted development.
Updated on May 29, 2020Comments
-
dkinzer almost 4 years
Have you ever taken a look under the hood at the jQuery 1.4 source code and noticed how it's encapsulated in the following way:
(function( window, undefined ) { //All the JQuery code here ... })(window);
I've read an article on JavaScript Namespacing and another one called "An Important Pair of Parens," so I know some about what's going on here.
But I've never seen this particular syntax before. What is that
undefined
doing there? And why doeswindow
need to be passed and then appear at the end again?-
Mottie over 13 yearsI wanted to add that Paul Irish talks about this in this video: paulirish.com/2010/10-things-i-learned-from-the-jquery-source
-
dkinzer almost 10 years@Bergi you marked my question as a duplicate of another but I asked the question almost a year before the duplicate. The cast should be the other way around.
-
Bergi almost 10 years@dkinzer: It's not about being asked earlier, it's about highest-quality answer. Admittedly, in this case it's neck and neck, but I found CMS' answer to be the best one. Come to chat.stackoverflow.com/rooms/17 to discuss this, though
-
Bergi over 9 years
-
-
dkinzer about 14 yearsThanks! that was a very informative video. I think you need to edit your response to say "the window variable is made local". I do think this is the best answer. I counted and found that the window object is called at least 17 times in the JQuery source code. So there's got to be a significant effect in moving the window into the Local Scope.
-
dkinzer about 14 yearsThanks. This makes a lot of sense. Though, I think the answer is a combination of this and what @C.Zakas says.
-
Vincent about 14 years@DKinzer Oh yes, you're rght, of course it's made local. Glad I could help you =)
-
Vincent about 14 years@DKinzer I'm afraid I'm not C. Zakas ;)
-
dkinzer about 14 years@Vincent, sorry about that :-)
-
gnarf over 13 years+1 for mentioning Minification , wish I could +2 for the jsperf -- The minified version is
(function(a,b){})(window);
--a
andb
are much shorter thanwindow
andundefined
:) -
user3167101 over 13 years+1 I had heard of scope chain before, but forgot the term. Thanks!
-
glmxndr over 13 yearsIt's also an alternative to using void(0) which was meant for the same reason: void(0) is a safe way to get the undefined value.
-
gnarf over 13 years"What you say" is in reference to this other question: stackoverflow.com/questions/4945265/…
-
David Tang over 13 years@gnarf, thanks for the notification that the questions were merged. I'll edit my answer to make a little more sense ;)
-
hexalys about 11 yearsAccording to this updated test jsperf.com/short-scope/5 passing 'window' is actually slower, when it come to get a window constant through jQuery, and particularly bad for Safari. So while 'undefined' has a use case, I am not quite convinced that 'window' is particularly useful in all cases.
-
Arman almost 11 yearsbtw, the global window.undefined can be overwritten in ECMAScript3 only, the ESCMASCript5 doesn't allow you this and the most of browsers run under ECMAScript5 standard nowadays. I guess IE7 allows to override the undefined global. IE8+ is OK.
-
TLindig almost 11 yearsIt has also a positive effect for minifying the code. So every usage of "window" and "undefined" can be replaced with a shorter name by the minifyer.
-
Akash Kava almost 11 yearsNot to mention, closure carries all variable along with instance of function, so if you have 100 bytes in closure, and 1000 instances that is 100kb of more memory.
-
Akash Kava almost 11 yearsSo wouldn't var window ={}; will not do same trick in window less script?
-
Akash Kava almost 11 years@dkinzer do you have any statistics that backs your significance?
-
JLRishe over 9 years@lukas.pukenis When you're making a library that's used in millions of websites, it's wise not to make assumptions about what madmen will do.
-
gabereal over 9 years@AkashKava and @Semra, i don't think this test really accounts for why you would pass in window in a real world situation. The performance gain is only going to be seen when you have deeply nested closures that access that variable further along the scope chain. obviously if your function is only one step away on the scope chain from the variable, you won't see much gain. but if it was waaaay down there and needed to get
window
you might see some gain by a local copy. -
Akash Kava over 9 years@gabereal new JavaScript engines resolves closures at time of compilation itself, there is no performance gain in closure at runtime. I doubt there is any measurable performance gain, if you are so confident, you can create jsperf example to demonstrate performance. The only performance we get is by isolating closures which results in better minification which reduces size and performance is achieved by faster download and parsing of script.
-
gabereal over 9 years@AkashKava what makes you think i'm so confident? I just said "might see some gain" and "i don't think". I could create a test, but i'd rather not since i never use this pattern anyway. can you explain what you mean by "resolves closures at time of compilation itself"? as opposed to what alternative? how did Javascript engines do things differently before?
-
Lars Gyrup Brink Nielsen about 8 yearsYou can pass
this
to the IIFE instead ofwindow
to get the global scope in both browser and node.js environments. Example:(function (root, undefined) { 'use strict'; var $ = root.jQuery; }(this));
-
Anirudha almost 8 yearsAs per ECMAScript 5, now undefined is not writable,configurable so its not an issue anymore in modern browsers even if its not strict. Can you please mention this in your answer..
-
Webwoman over 5 yearsHave a find a code where window is curried at the end but not entered in the function's parameters, what does mean? it ensure that the parameters follow the original global's scope object even if there isn't any window param I assume?