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