I have been reading a lot of Javascript lately and I have been noticing that the whole file is wrapped like the following in the .js files to be imported.
(function() {
...
code
...
})();
What is the reason for doing this rather than a simple set of constructor functions?
This question is related to
javascript
scope
coding-style
iife
In its simplest form, this technique aims to wrap code inside a function scope.
It helps decreases chances of:
It does not detect when the document is ready - it is not some kind of document.onload
nor window.onload
It is commonly known as an Immediately Invoked Function Expression (IIFE)
or Self Executing Anonymous Function
.
var someFunction = function(){ console.log('wagwan!'); };
(function() { /* function scope starts here */
console.log('start of IIFE');
var myNumber = 4; /* number variable declaration */
var myFunction = function(){ /* function variable declaration */
console.log('formidable!');
};
var myObject = { /* object variable declaration */
anotherNumber : 1001,
anotherFunc : function(){ console.log('formidable!'); }
};
console.log('end of IIFE');
})(); /* function scope ends */
someFunction(); // reachable, hence works: see in the console
myFunction(); // unreachable, will throw an error, see in the console
myObject.anotherFunc(); // unreachable, will throw an error, see in the console
In the example above, any variable defined in the function (i.e. declared using var
) will be "private" and accessible within the function scope ONLY (as Vivin Paliath puts it). In other words, these variables are not visible/reachable outside the function. See live demo.
Javascript has function scoping. "Parameters and variables defined in a function are not visible outside of the function, and that a variable defined anywhere within a function is visible everywhere within the function." (from "Javascript: The Good Parts").
In the end, the code posted before could also be done as follows:
var someFunction = function(){ console.log('wagwan!'); };
var myMainFunction = function() {
console.log('start of IIFE');
var myNumber = 4;
var myFunction = function(){ console.log('formidable!'); };
var myObject = {
anotherNumber : 1001,
anotherFunc : function(){ console.log('formidable!'); }
};
console.log('end of IIFE');
};
myMainFunction(); // I CALL "myMainFunction" FUNCTION HERE
someFunction(); // reachable, hence works: see in the console
myFunction(); // unreachable, will throw an error, see in the console
myObject.anotherFunc(); // unreachable, will throw an error, see in the console
One day, someone probably thought "there must be a way to avoid naming 'myMainFunction', since all we want is to execute it immediately."
If you go back to the basics, you find out that:
expression
: something evaluating to a value. i.e. 3+11/x
statement
: line(s) of code doing something BUT it does not evaluate to a value. i.e. if(){}
Similarly, function expressions evaluate to a value. And one consequence (I assume?) is that they can be immediately invoked:
var italianSayinSomething = function(){ console.log('mamamia!'); }();
So our more complex example becomes:
var someFunction = function(){ console.log('wagwan!'); };
var myMainFunction = function() {
console.log('start of IIFE');
var myNumber = 4;
var myFunction = function(){ console.log('formidable!'); };
var myObject = {
anotherNumber : 1001,
anotherFunc : function(){ console.log('formidable!'); }
};
console.log('end of IIFE');
}();
someFunction(); // reachable, hence works: see in the console
myFunction(); // unreachable, will throw an error, see in the console
myObject.anotherFunc(); // unreachable, will throw an error, see in the console
The next step is the thought "why have var myMainFunction =
if we don't even use it!?".
The answer is simple: try removing this, such as below:
function(){ console.log('mamamia!'); }();
It won't work because "function declarations are not invokable".
The trick is that by removing var myMainFunction =
we transformed the function expression into a function declaration. See the links in "Resources" for more details on this.
The next question is "why can't I keep it as a function expression with something other than var myMainFunction =
?
The answer is "you can", and there are actually many ways you could do this: adding a +
, a !
, a -
, or maybe wrapping in a pair of parenthesis (as it's now done by convention), and more I believe. As example:
(function(){ console.log('mamamia!'); })(); // live demo: jsbin.com/zokuwodoco/1/edit?js,console.
or
+function(){ console.log('mamamia!'); }(); // live demo: jsbin.com/wuwipiyazi/1/edit?js,console
or
-function(){ console.log('mamamia!'); }(); // live demo: jsbin.com/wejupaheva/1/edit?js,console
So once the relevant modification is added to what was once our "Alternative Code", we return to the exact same code as the one used in the "Code Explained" example
var someFunction = function(){ console.log('wagwan!'); };
(function() {
console.log('start of IIFE');
var myNumber = 4;
var myFunction = function(){ console.log('formidable!'); };
var myObject = {
anotherNumber : 1001,
anotherFunc : function(){ console.log('formidable!'); }
};
console.log('end of IIFE');
})();
someFunction(); // reachable, hence works: see in the console
myFunction(); // unreachable, will throw an error, see in the console
myObject.anotherFunc(); // unreachable, will throw an error, see in the console
Read more about Expressions vs Statements
:
One thing one might wonder is "what happens when you do NOT define the variable 'properly' inside the function -- i.e. do a simple assignment instead?"
(function() {
var myNumber = 4; /* number variable declaration */
var myFunction = function(){ /* function variable declaration */
console.log('formidable!');
};
var myObject = { /* object variable declaration */
anotherNumber : 1001,
anotherFunc : function(){ console.log('formidable!'); }
};
myOtherFunction = function(){ /* oops, an assignment instead of a declaration */
console.log('haha. got ya!');
};
})();
myOtherFunction(); // reachable, hence works: see in the console
window.myOtherFunction(); // works in the browser, myOtherFunction is then in the global scope
myFunction(); // unreachable, will throw an error, see in the console
Basically, if a variable that was not declared in its current scope is assigned a value, then "a look up the scope chain occurs until it finds the variable or hits the global scope (at which point it will create it)".
When in a browser environment (vs a server environment like nodejs) the global scope is defined by the window
object. Hence we can do window.myOtherFunction()
.
My "Good practices" tip on this topic is to always use var
when defining anything: whether it's a number, object or function, & even when in the global scope. This makes the code much simpler.
Note:
block scope
(Update: block scope local variables added in ES6.)function scope
& global scope
(window
scope in a browser environment)Read more about Javascript Scopes
:
Once you get this IIFE
concept, it leads to the module pattern
, which is commonly done by leveraging this IIFE pattern. Have fun :)
We should also use 'use strict' in the scope function to make sure that the code should be executed in "strict mode". Sample code shown below
(function() {
'use strict';
//Your code from here
})();
Javascript in a browser only really has a couple of effective scopes: function scope and global scope.
If a variable isn't in function scope, it's in global scope. And global variables are generally bad, so this is a construct to keep a library's variables to itself.
You can use function closures as data in larger expressions as well, as in this method of determining browser support for some of the html5 objects.
navigator.html5={
canvas: (function(){
var dc= document.createElement('canvas');
if(!dc.getContext) return 0;
var c= dc.getContext('2d');
return typeof c.fillText== 'function'? 2: 1;
})(),
localStorage: (function(){
return !!window.localStorage;
})(),
webworkers: (function(){
return !!window.Worker;
})(),
offline: (function(){
return !!window.applicationCache;
})()
}
In addition to keeping the variables local, one very handy use is when writing a library using a global variable, you can give it a shorter variable name to use within the library. It's often used in writing jQuery plugins, since jQuery allows you to disable the $ variable pointing to jQuery, using jQuery.noConflict(). In case it is disabled, your code can still use $ and not break if you just do:
(function($) { ...code...})(jQuery);
That's called a closure. It basically seals the code inside the function so that other libraries don't interfere with it. It's similar to creating a namespace in compiled languages.
Example. Suppose I write:
(function() {
var x = 2;
// do stuff with x
})();
Now other libraries cannot access the variable x
I created to use in my library.
Source: Stackoverflow.com