aka IIFE (pronounced "iffy")
Coined by Ben Alman, @cowboy
(function(){
// Code goes here...
})();
The function expression is called once as soon as it is evaluated and never run again.
(function(){
// Any code in this function
// is run immediately
})(); //<-- Brackets invoke the function
There are two ways of defining functions:
// Function declaration:
function foo() { }
// Function expression:
var foo = function() { };
You can only immediately invoke function expressions, not function declarations.
// This is NOT valid syntax:
function() { /* ... */ }();
// The parentheses around the function
// turn it into a function expression
(function() { /* ... */ })();
// Function expressions don't need them...
var foo = function() { /* ... */ }();
However, this is the preferred syntax:
var foo = (function() { /* ... */ })();
The parentheses help indicate that it's an IIFE.
Although parentheses are the preferred method, any of the following will also work.
!function() { /* ... */ }();
+function() { /* ... */ }();
-function() { /* ... */ }();
~function() { /* ... */ }();
new function() { /* ... */ };
new function(arg) { /* ... */ }(arg);
First and last lines of the jQuery source:
(function( window, undefined ) {
// Snip...
})( window );
Notice var called 'undefined', which is undefined.
Seal your code in a new scope, alias the global jQuery function as $:
(function( $ ) {
// Snip...
})( jQuery );
First and last lines of the Backbone.js source:
(function(){
// Snip...
}).call(this);
Notice Backbone.js uses the 'call' syntax variation.
First and last lines of any script compiled from CoffeeScript using default settings:
(function() {
// Snip...
}).call(this);
Animation loop which runs immediately and calls itself again once completed.
(function animloop(){
window.requestAnimationFrame(animloop);
render();
})();
/* lib.js */
(function() {
window.public = 'foo';
var private = 'bar';
})();
/* script.js */
public; // 'foo'
private; // undefined
Returning from an IIFE evaluates to a single value:
var browser = {
vendorPrefix: (function(){
var prefix;
// Detect vendor prefix...
return prefix;
})()
};
var MyClass = (function(){
function MyClass(foo) {
this.foo = foo;
}
MyClass.prototype = {
bar: 'baz'
};
return MyClass;
})();
class Foo //Compiles to:
var Foo;
Foo = (function() {
Foo.name = 'Foo';
function Foo() {}
return Foo;
})();
for (var i = 1; i <= 3; i++) {
(function(i){
// All variables (including i)
// are now scoped to this block
// On click, alerts '1', '2' and '3'
$elem.click(function() { alert(i); });
})(i);
}
Javascript has lexical (function) scope, so i is shared by all functions created in this loop.
The IIFE locks in i's value, otherwise we get this:
for (var i = 1; i <= 3; i++) {
// On click, alerts '4', '4' and '4' :(
$elem.click(function() { alert(i); });
}
do (i) -> console.log i
Compiles to:
(function(i) {
return console.log(i);
})(i);
The revealing module pattern ('num' is private):
var number = (function(){
var num = 0,
add = function(n) { num = num + n; },
get = function() { return num; };
return { add: add, get: get };
})();
var foo = (function(){
var priv = function() { alert('Hi!'); },
publ = function() { priv(); };
return publ;
})();
'foo' is now a function that calls the private 'priv' function (available via a closure).
A closure is created when a function is returned from another function, retaining its original scope.
var foo = (function() {
var bar = 'baz';
return function() { return bar; };
})();
foo(); // Returns the value of 'bar'
bar; // Undefined, out of scope
function makeAlert(i) {
return function() {
alert(i)
}
}
for (var i = 1; i <= 3; i++) {
// On click, alerts '1', '2' and '3' :D
$elem.click(makeAlert(i));
}
What IIFEs used to be called (mistakenly).
Why is this term incorrect?
This anonymous function literally executes itself:
var foo = function() {
if (arguments.callee.caller ===
arguments.callee) {
return; // ...if foo called foo
}
arguments.callee(); // <- Self-execute
};
In ECMAScript 5, 'arguments.callee' is deprecated in favour of using named function expressions:
var foo = function bar() {
if (bar.caller === bar) {
return;
}
bar();
};
Slides: bit.ly/gettingclosure