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]
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.
Examples
The key to understanding design patterns such as immediately invoked function expressions is to realize that until recently JavaScript had only function scope (but not block scope) and passes values by reference inside a closure.[5] This is no longer entirely true, in the latest version of JavaScript block scoping is available and becomes evident when using the new let
and const
keywords.[6]
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 that 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.[7]
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.[8]
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.[9] While Herman's example is deliberately convoluted, it arises directly from the same lack of block scope.[10]
Establishing private variables and accessors
IIFEs are also useful for establishing private methods for accessible functions while still exposing some properties for later use.[11] 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 that has also been referred to as a "self-executing anonymous function".[1][12] However, immediately invoked functions do not need to be anonymous, and ECMAScript 5's strict mode forbids arguments.callee
,[13] making the latter term less accurate.[3][8]
In lambda calculus, this construct was referred to as "redex", for reducible expression, see Reduction strategy.
References
- ^ a b c d Alman, Ben (15 November 2010). invoked-function-expression/ "Immediately Invoked Function Expressions". Archived from invoked-function-expression the original on 1 December 2017. Retrieved 4 February 2013.
{{cite web}}
: Check|archive-url=
value (help); Check|url=
value (help); Unknown parameter|dead-url=
ignored (|url-status=
suggested) (help) - ^ Resig, John (2006). Pro JavaScript Techniques. Apress. p. 29. ISBN 978-1-4302-0283-7.
- ^ a b Osmani, Addy (2012). Learning JavaScript Design Patterns. O'Reilly. p. 206. ISBN 978-1-4493-3487-1.
- ^ Baagoe, Johannes. "Closing parenthesis in function's definition followed by its call". Retrieved 19 April 2010.
- ^ Haverbeke, Marijn (2011). Eloquent JavaScript. No Starch Press. pp. 29–30. ISBN 978-1-59327-282-1.
- ^ ECMAScript 6: New Features: Overview & Comparison, Block-Scoped Variables
- ^ Alman, Ben. "simple-iife-example.js". Github. Retrieved 5 February 2013.
- ^ a b Otero, Cesar; Larsen, Rob (2012). Professional jQuery. John Wiley & Sons. p. 31. ISBN 978-1-118-22211-9.
- ^ Herman, David (2012). Effective Javascript. Addison-Wesley. pp. 44–45. ISBN 978-0-321-81218-6.
- ^ Zakas, Nicholas C. (2011). "Mimicking Block Scope". Professional JavaScript for Web Developers. John Wiley & Sons. ISBN 978-1-118-23309-2.
- ^ Rettig, Pascal (2012). Professional HTML5 Mobile Game Development. John Wiley & Sons. p. 145. ISBN 978-1-118-30133-3.
- ^ Cite error: The named reference
Enlighten
was invoked but never defined (see the help page). - ^ "Strict mode". Mozilla JavaScript Reference. Mozilla Developer Network. Retrieved 4 February 2013.
External links
- "Functions and function scope". Mozilla JavaScript Reference. Mozilla Developer Network. Retrieved 4 February 2013.
- Soshnikov, Dmitry. "ECMA-262-3 in detail. Chapter 5. Functions". Archived from the original on 1 December 2017. Retrieved 4 February 2013.
{{cite web}}
: Unknown parameter|dead-url=
ignored (|url-status=
suggested) (help)