Content deleted Content added
→Examples: clarify re: block scope |
m Added additional way to pass variables into IIFE |
||
(47 intermediate revisions by 33 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 of supporting [[modular programming]] before the introduction of more standardized solutions such as [[CommonJS]] and [[ECMAScript#6th Edition – ECMAScript 2015|ES modules]].<ref>{{cite web |last1=McGinnis |first1=Tyler |title=JavaScript Modules: From IIFEs to CommonJS to ES6 Modules |url=https://ui.dev/javascript-modules-iifes-commonjs-esmodules/ |website=ui.dev |access-date=18 August 2021 |language=en |date=15 January 2019}}</ref>
An '''immediately-invoked function expression''' (or '''IIFE''', pronounced "iffy"<ref name=Alman>{{cite web|last=Alman|first=Ben|title=Immediately Invoked Function Expressions|url=http://benalman.com/news/2010/11/immediately-invoked-function-expression|year=2010|accessdate=4 February 2013}}</ref>) is a [[JavaScript]] [[Programming_idiom|programming language idiom]] which produces a [[scope (computer science)|lexical scope]] using JavaScript's [[function scoping]]. Immediately-invoked function expressions can be used to avoid [[JavaScript syntax#Scoping_and_hoisting|variable hoisting]] from within blocks, protect against polluting the [[Global variable|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''',<ref>{{cite book|last=Resig|first=John|title=Pro JavaScript Techniques|year=2006|publisher=Apress|isbn=9781430202837|pages=29}}</ref> 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.<ref name=Alman /><ref name=Osmani>{{cite book|last=Osmani|first=Addy|title=Learning JavaScript Design Patterns|year=2012|publisher=O'Reilly|isbn=9781449334871|pages=206}}</ref><ref>{{cite news|last1=Baagoe|first1=Johannes|title=Closing parenthesis in function's definition followed by its call|url=https://groups.google.com/forum/#!topic/comp.lang.javascript/tjVn1NjGDN8%5B1-25%5D|accessdate=19 April 2010}}</ref>▼
Immediately invoked function expressions can be used to avoid [[JavaScript syntax#Scoping and hoisting|variable hoisting]] from within blocks, protecting against polluting the [[Global variable|global environment]] and simultaneously allowing public access to methods while retaining privacy for variables defined within the function. In other words, it wraps functions and variables, keeping them out of the global scope and giving them a local scope.
==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=9781449342883|pages=61}}</ref> A [[Coding conventions|common convention]] is to enclose the function expression (and optionally its invocation operator) with the ''grouping operator'',<ref>{{cite web|url=https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Grouping|title=Grouping operator|publisher=Mozilla Developer Network}}</ref> i.e. in parentheses, to explicitly tell the parser 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=9781449327682|pages=44}}</ref><ref>{{cite web|url=http://exploringjs.com/es6/ch_arrow-functions.html#iiaf|title=ExploringJS|author=Axel Rauschmayer}}</ref>▼
▲== Usage ==
▲Immediately
<syntaxhighlight lang="JavaScript">
(function () { /* ... */ })();
(function () { /* ... */ }());
(() => { /* ... */ })(); // With ES6 arrow functions (though parentheses only allowed on outside)
</syntaxhighlight>▼
<syntaxhighlight lang="JavaScript">▼
!function () { /* ... */ }();▼
</syntaxhighlight>
In contexts where an expression is expected, wrapping in parentheses is not necessary:
<syntaxhighlight lang="
true && function () { /* ... */ }();
0, function () { /* ... */ }();
Line 27 ⟶ 21:
Passing variables into the scope is done as follows:
<syntaxhighlight lang="
(function(a, b) { /* ... */ })("hello", "world");
</syntaxhighlight>
An initial parenthesis is one case where the
<syntaxhighlight lang="JavaScript">
a = b + c
Line 38 ⟶ 33:
})();
</syntaxhighlight>
==Examples==
The key to understanding design patterns such as
// 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
===Evaluation context===▼
const foo = 1;
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> ▼
let bar = 2;
<syntaxhighlight lang="JavaScript">▼
{
var v, getValue;▼
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
v = 1;
getValue = function () { return v; };
v = 2;
getValue(); // 2
</syntaxhighlight>
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. ▼
▲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|last=Otero|first=Cesar|last2=Larsen|first2=Rob|title=Professional jQuery|year=2012|publisher=John Wiley & Sons|isbn=9781118222119|pages=31}}</ref> ▼
▲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="JavaScript">▼
var v, getValue;▼
v = 1;
getValue = (function (x) {
Line 70 ⟶ 84:
This is equivalent to the following code:
<syntaxhighlight lang="
v = 1;
function f(x) {
Line 82 ⟶ 96:
</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=
▲===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=9781118301333|pages=145}}</ref> The following example comes from Alman's post on IIFEs.<ref name=Alman />
// "counter" is a function that returns an object with properties, which in this case are functions.
return {
Line 106 ⟶ 118:
// These calls access the function properties returned by "counter".
counter.get(); // 0
counter.set(3);
counter.increment();
counter.increment();
</syntaxhighlight>
If we attempt to access <code>counter.i</code> from the global environment, it will be undefined, as it is enclosed within the invoked function and is not a property of <code>counter</code>. Likewise, if we attempt to access <code>i</code>, it will result in an error, as we have not declared <code>i</code> 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".<ref name=Alman /><ref name=Enlighten /> However, immediately-invoked functions do not need to be anonymous, and [[ECMAScript]] 5's strict mode forbids <code>arguments.callee</code>,<ref>{{cite web|title=Strict mode|url=https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Functions_and_function_scope/Strict_mode#Making_eval_and_arguments_simpler|work=Mozilla JavaScript Reference|publisher=Mozilla Developer Network|accessdate=4 February 2013}}</ref> making the latter term less accurate.<ref name=Osmani /><ref name=JQ />▼
▲
==
*[[Evaluation strategy]]
{{reflist|30em}}▼
==
▲{{reflist|30em}}
* ''{{cite web|title=Functions and function scope|url=https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Functions_and_function_scope|work=Mozilla JavaScript Reference|publisher=Mozilla Developer Network|accessdate=4 February 2013}}'' ▼
== External links ==
▲*
[[Category:JavaScript]]
[[Category:Programming language concepts]]
|