The IIFE/SEFE/closure/whatever
A quick discussion why we use "closures" for creating our code is that the purpose of the closure/IIFE/SEFE/whatever you want to call it, is to provide a scope where you are free to declare any variables for the internals to use, without polluting the global scope:
(function(ns){
//I can declare tons of variables and functions here
var a,b,c,d,e,f,g ...;
//expose only foo to the namespace
ns.foo = function(){
//and foo can use them here
}
}(this.myNS = this.myNS || {}));
//but out here, we call foo, use those variables
//but none of those variables are visible
myNS.foo();
//no a,b,c,d,e,f,g ... out here
window
Now, in the case of window
, the idea that they are passed into the function is to have a local reference of whatever was pointed by them. It's because of the usage of that IIFE/SEFE/closure and how the compiler works.
//-3-found "a" here
var a = 1
(function(ns){
//-2-no "a" here, going up
ns.foo = function(){
//-1-no "a" here, going up
console.log(a);
}
}(this.myNS = this.myNS || {}));
myNS.foo();
A quick trip into the how the compiler works is that when it tries to look for a variable/function, it searches through the local function scope first. If that variable/function is not found, it will look for it in the outer/containing scope. This goes on until the compiler finds that value or when you reach the global scope and declares it as non-existent.
In the code above, you crossed 2 scopes in order to find a
. If a
was declared lower into the scope, you could have minimized crossings. Now, wouldn't it be better if you provided window locally instead of having the compiler find it? YES, although:
- performance gain is almost negligible
- code structure might be more important than this minor optimization
undefined
For undefined
, it's because undefined
is mutable (it's not constant/final). Its value can be changed so that it would not be undefined
anymore (but somewhat "pseudo-defined"). A quick code about that can be found here:
var a = {};
a.b === undefined; // true because property b is not set
undefined = 42;
a.b === undefined; // false, because undefined is something else
So what they did to overcome this "definable undefined
" was to pass nothing into the function, and by default, passing nothing to the function and naming it something in the function gives it the value of "true undefined
".
Personally, I don't pass in window
and undefined
into my closure for some reasons:
I don't check potentially undefined values against undefined
. Since undefined values are falsy, loose comparison will tell if it is undefined or more like "unusable":
//instead of this:
if(potentiallyUndefined === undefined){...do stuff...}
if(typeof potentiallyUndefined === 'undefined'){...do stuff...}
//you can do this
if(potentiallyUndefined){...do stuff...}
Like I said, it's a minor/negligible performance gain, so I don't pass in window
. Besides, how much of my code uses window
anyway?
var
s. \$\endgroup\$