Immediately-invoked function expression

An immediately-invoked function expression (or IIFE, pronounced "iffy"[1]) is a JavaScript programming language idiom which produces a lexical scope using JavaScript's function scoping. Immediately-invoked function expressions can be used to avoid variable hoisting from within blocks, protect against polluting the global environment and simultaneously allow public access to methods while retaining privacy for variables defined within the function. This concept has been referred to as a self-executing anonymous function,[2] but Ben Alman introduced the term IIFE as a more semantically accurate term for the idiom, shortly after its discussion arose on comp.lang.javascript.[1][3] [4]

Usage

Immediately-invoked function expressions may be written in a number of different ways.[5] A common convention is to enclose the function expression (and optionally its invocation operator—Douglas Crockford's style) in parentheses to explicitly tell the parser to expect an expression, since in JavaScript parentheses can't contain statements. Otherwise, in most situations, when the parser encounters the function keyword, it treats it as a function declaration (statement), and not as a function expression.[6][7]

(function () {  })();
(function () {  }());  // Douglas Crockford's style

There are other ways to enforce a function expression:

!function () {  }();
~function () {  }();
-function () {  }();
+function () {  }();

In contexts where an expression is expected, wrapping in parentheses is not necessary:

var f = function () {  }();
true && function () {  }();
0, function () {  }();

Passing variables into the scope is done as follows:

(function(a, b) {  })("hello", "world");

An initial parenthesis is one case where the automatic semicolon insertion (ASI) in JavaScript can cause problems; the expression is instead interpreted as a call to the last term on the preceding line. In some styles that omit optional semicolons, the semicolon is placed in front of the parenthesis, and is known as a defensive semicolon.[8][9] For example:

a = b + c
;(function () {
  // code
})();

…to avoid being parsed as c(…).

Examples

The key to understanding design patterns such as immediately-invoked function expressions is to realize JavaScript has function scope (but not block scope) and passes values by reference inside a closure.[10] (This is no longer entirely true, in the latest version of JavaScript block scoping does exist thanks to the new let keyword.[11])

Evaluation context

A lack of block scope means that variables defined inside, for example, a for loop will have their definition "hoisted" to the top of the enclosing function. Evaluating a function which depends on variables modified by the outer function (including by iteration) can be difficult. We can see this without a loop if we update a value between defining and invoking the function.[12]

var v, getValue;
v = 1;
getValue = function () { return v; };
v = 2;
 
getValue(); // 2

While the result may seem obvious when updating v manually, it can produce unintended results when getValue() is defined inside a loop.

Hereafter the function passes v as an argument and is invoked immediately, preserving the inner function's execution context.[13]

var v, getValue;
v = 1;
getValue = (function (x) {
    return function () { return x; };
})(v);
v = 2;

getValue();  // 1

This is equivalent to the following code:

var v, getValue;
v = 1;
function f(x) {
    return function () { return x; };
};
getValue = f(v);
v = 2;

getValue();  // 1

David Herman's Effective JavaScript contains an example illustrating the problems of evaluation context inside loops.[14] While Herman's example is deliberately convoluted it arises directly from the same lack of block scope.[15]

Establishing private variables and accessors

IIFEs are also useful for establishing private methods for accessible functions while still exposing some properties for later use.[16] The following example comes from Alman's post on IIFEs.[1]

// "counter" is a function that returns an object with properties, which in this case are functions.
var counter = (function () {
    var i = 0;

    return {
        get: function () {
            return i;
        },
        set: function (val) {
            i = val;
        },
        increment: function () {
            return ++i;
        }
    };
})();

// These calls access the function properties returned by "counter".
counter.get();  // 0
counter.set(3);
counter.increment();  // 4
counter.increment();  // 5

If we attempt to access counter.i from the global environment, it will be undefined as it is enclosed within the invoked function and is not a property of counter. Likewise, if we attempt to access i it will result in an error as we have not declared i in the global environment.

Terminology

"Immediately-invoked function expression" as a term describes a design pattern which has also been referred to as a "self-executing anonymous function."[1][5] However, immediately-invoked functions need not be anonymous and ECMAScript 5's strict mode forbids arguments.callee,[17] making the latter term less accurate.[3][13]

In lambda-calculus, this construct was referred to as "redex", for reducible expression, see Reduction strategy (code optimization).

References

  1. 1 2 3 4 Alman, Ben (2010). "Immediately Invoked Function Expressions". Retrieved 4 February 2013.
  2. Resig, John (2006). Pro JavaScript Techniques. Apress. p. 29. ISBN 9781430202837.
  3. 1 2 Osmani, Addy (2012). Learning JavaScript Design Patterns. O'Reilly. p. 206. ISBN 9781449334871.
  4. Baagoe, Johannes. "Closing parenthesis in function's definition followed by its call". Retrieved 19 April 2010.
  5. 1 2 Lindley, Cody (2013). JavaScript Enlightenment. O'Reilly. p. 61. ISBN 9781449342883.
  6. Zakas, Nicholas (2012). Maintainable JavaScript. O'Reilly. p. 44. ISBN 9781449327682.
  7. Crockford, Douglas. "Code Conventions for the JavaScript Programming Language". Retrieved 3 February 2013.
  8. "JavaScript Semicolon Insertion: Everything you need to know", Friday, May 28, 2010
  9. "Semicolons in JavaScript are optional", by Mislav Marohnić, 07 May 2010
  10. Haverbeke, Marijn (2011). Eloquent JavaScript. No Starch Press. pp. 29–30. ISBN 9781593272821.
  11. Alman, Ben. "simple-iife-example.js". Github. Retrieved 5 February 2013.
  12. 1 2 Otero, Cesar; Larsen, Rob (2012). Professional jQuery. John Wiley & Sons. p. 31. ISBN 9781118222119.
  13. Herman, David (2012). Effective Javascript. Addison-Wesley. pp. 44–45. ISBN 9780321812186.
  14. Zakas, Nicholas C. (2011). "Mimicking Block Scope". Professional JavaScript for Web Developers. John Wiley & Sons. ISBN 9781118233092.
  15. Rettig, Pascal (2012). Professional HTML5 Mobile Game Development. John Wiley & Sons. p. 145. ISBN 9781118301333.
  16. "Strict mode". Mozilla JavaScript Reference. Mozilla Developer Network. Retrieved 4 February 2013.

External links

This article is issued from Wikipedia - version of the 11/3/2016. The text is available under the Creative Commons Attribution/Share Alike but additional terms may apply for the media files.