Content deleted Content added
reword intro. the idiom is notable for being used in Javascript, but it's not a Javascript-only idiom. Also it's basically dead because modules got added to ES6 |
m Added additional way to pass variables into IIFE |
||
(28 intermediate revisions by 18 users not shown) | |||
Line 1:
{{Short description|Javascript design pattern}}
An '''immediately invoked function expression''' (or '''IIFE''', pronounced "iffy", [[International Phonetic Alphabet|IPA]] /ˈɪf.i/) is a [[Programming idiom|programming language idiom]] which produces a [[scope (computer science)|lexical scope]] using [[function scoping]]. It was popular in [[JavaScript]]<ref name="Alman">{{cite web|url=http://benalman.com/news/2010/11/immediately-invoked-function-expression/|title=Immediately Invoked Function Expressions|last=Alman|first=Ben|date=15 November 2010|website=|url-status=live|archive-url=https://web.archive.org/web/20171201033208/http://benalman.com/news/2010/11/immediately-invoked-function-expression/|archive-date=1 December 2017|accessdate=18 January 2019}}</ref> as a method
Immediately invoked function expressions can be used to avoid [[JavaScript syntax#Scoping and hoisting|variable hoisting]] from within blocks,
== Usage ==
Immediately invoked function expressions may be written in a number of different ways.<ref name=Enlighten>{{cite book |last=Lindley |first=Cody |title=JavaScript Enlightenment |year=2013 |publisher=O'Reilly |isbn=978-1-4493-4288-3 |page=61}}</ref> A [[Coding conventions|common convention]] is to enclose the function expression{{spnd}}and optionally its invocation operator{{spnd}}with the grouping operator,<ref>{{cite web |url=https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Grouping |title=Grouping operator |date=2 October 2023 |publisher=Mozilla Developer Network}}</ref> in parentheses, to tell the parser explicitly to expect an expression. Otherwise, in most situations, when the parser encounters the <code>function</code> keyword, it treats it as a function declaration (statement), and not as a function expression.<ref>{{cite book |last=Zakas |first=Nicholas |title=Maintainable JavaScript |year=2012 |publisher=O'Reilly |isbn=978-1-4493-2768-2 |page=44}}</ref><ref>{{cite web |url=http://exploringjs.com/es6/ch_arrow-functions.html#iiaf |title=ExploringJS |author=Axel Rauschmayer}}</ref>
<syntaxhighlight lang="JavaScript">
(function () { /* ... */ })();
(function () { /* ... */ }());
(() => { /* ... */ })(); // With ES6 arrow functions (though parentheses only allowed on outside)
</syntaxhighlight>▼
!function () { /* ... */ }();▼
</syntaxhighlight>
In contexts where an expression is expected, wrapping in parentheses is not necessary:
<syntaxhighlight lang="
true && function () { /* ... */ }();
0, function () { /* ... */ }();
Line 29 ⟶ 21:
Passing variables into the scope is done as follows:
<syntaxhighlight lang="
(function(a, b) { /* ... */ })("hello", "world");
</syntaxhighlight>
Line 43 ⟶ 36:
==Examples==
The key to understanding design patterns such as IIFE is to realize that prior to ES6, JavaScript only featured [[Scope (computer science)#Function scope|function scope]] (thus lacking [[Scope (computer science)#Block scope|block scope]]), passing [[Call_by_reference|values by reference]] inside [[Closure (computer science)|closure]]s.<ref>{{cite book |last=Haverbeke |first=Marijn |title=Eloquent JavaScript |year=2011 |publisher=No Starch Press |isbn=978-1-59327-282-1 |pages=29–30}}</ref> This is no longer the case, as the ES6 version of JavaScript implements block scoping using the new <code>let</code> and <code>const</code> keywords.<ref>
// Before ES6: Creating a scope using an IIFE
var foo = 1;
var bar = 2;
(function(){
var foo = 3; // shadows the outer `foo`
bar = 4; // overwrites the outer `bar`
})();
console.log(foo, bar); // 1 4
// Since ES6: Creating a scope using curly brackets in combination with let and const
const foo = 1;
let bar = 2;
{
const foo = 3; // shadows the outer `foo`
bar = 4; // overwrites the outer `bar`
}
console.log(foo, bar); // 1 4
▲</syntaxhighlight>
=== 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.<ref>{{cite web |last=Alman |first=Ben |title=simple-iife-example.js |url=https://gist.github.com/cowboy/4710214 |work=Github |accessdate=5 February 2013}}</ref>
<syntaxhighlight lang="
v = 1;
getValue = function () { return v; };
Line 58 ⟶ 70:
While the result may seem obvious when updating <code>v</code> manually, it can produce unintended results when <code>getValue()</code> is defined inside a loop.
Hereafter the function passes <code>v</code> as an argument and is invoked immediately, preserving the inner function's execution context.<ref name=JQ>{{cite book |
<syntaxhighlight lang="
v = 1;
getValue = (function (x) {
Line 72 ⟶ 84:
This is equivalent to the following code:
<syntaxhighlight lang="
v = 1;
function f(x) {
Line 83 ⟶ 95:
getValue(); // 1
</syntaxhighlight>
=== Establishing private variables and accessors ===
IIFEs are also useful for establishing private methods for accessible functions while still exposing some properties for later use.<ref>{{cite book |last=Rettig |first=Pascal |title=Professional HTML5 Mobile Game Development |year=2012 |publisher=John Wiley & Sons |isbn=978-1-118-30133-3 |page=145}}</ref> The following example comes from Alman's post on IIFEs.<ref name=Alman/>
<syntaxhighlight lang="
// "counter" is a function that returns an object with properties, which in this case are functions.
return {
|