Immediately invoked function expression: Difference between revisions

Content deleted Content added
DenSchub (talk | contribs)
m DenSchub moved page Immediately-invoked function expression to Immediately invoked function expression: -ly adverbs cannot be hyphenated
MOD31P (talk | contribs)
m Added additional way to pass variables into IIFE
 
(44 intermediate revisions by 31 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 |last=Alman |first=Ben |title=Immediately Invoked Function Expressions |url=http://benalman.com/news/2010/11/immediately-invoked-function-expression/|title=Immediately Invoked Function Expressions|last=Alman|first=Ben|date=15 November 2010 |accessdatewebsite=4 February 2013 |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 |dead-urlaccessdate=no18 January 2019}}</ref> isas a [[JavaScript]]method of supporting [[Programmingmodular idiom|programming language idiom]] whichbefore producesthe aintroduction [[scopeof (computermore science)|lexicalstandardized scope]]solutions usingsuch JavaScript'sas [[function scopingCommonJS]]. Immediately-invoked function expressions can be used to avoidand [[JavaScript syntaxECMAScript#Scoping6th andEdition hoisting|variable hoisting]] from within blocks, protect against polluting the [[GlobalECMAScript variable2015|globalES environmentmodules]] 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 bookweb |lastlast1=ResigMcGinnis |firstfirst1=JohnTyler |title=Pro JavaScript TechniquesModules: |year=2006From |publisher=ApressIIFEs |isbn=978-1-4302-0283-7to |page=29}}</ref>CommonJS butto BenES6 AlmanModules introduced the term IIFE as a more semantically accurate term for the idiom, shortly after its discussion arose on comp.lang|url=https://ui.dev/javascript.<ref name=Alman/><ref name=Osmani>{{cite book |last=Osmani |first=Addy |title=Learning JavaScript Design Patterns |year=2012 |publisher=O'Reilly |isbn=978-1modules-4493iifes-3487commonjs-1 |page=206}}<esmodules/ref><ref>{{cite news |lastwebsite=Baagoeui.dev |firstaccess-date=Johannes18 |title=ClosingAugust parenthesis in function's definition followed by its call2021 |urllanguage=https://groups.google.com/forum/#!topic/comp.lang.javascript/tjVn1NjGDN8%5B1-25%5Den |accessdatedate=1915 AprilJanuary 20102019}}</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=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>
 
There are other ways to enforce a function expression:
<syntaxhighlight lang="JavaScript">
!function () { /* ... */ }();
~function () { /* ... */ }();
-function () { /* ... */ }();
+function () { /* ... */ }();
void function () { /* ... */ }();
</syntaxhighlight>
 
In contexts where an expression is expected, wrapping in parentheses is not necessary:
<syntaxhighlight lang="JavaScriptjavascript">
varlet f = function () { /* ... */ }();
true && function () { /* ... */ }();
0, function () { /* ... */ }();
Line 27 ⟶ 21:
 
Passing variables into the scope is done as follows:
<syntaxhighlight lang="JavaScriptjavascript">
(function(a, b) { /* ... */ })("hello", "world");
!(function (a="hello", b="world") { /* ... */ })(); //also works
</syntaxhighlight>
 
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]].<ref name=inimino>{{cite web |url=http://inimino.org/~inimino/blog/javascript_semicolons |title=JavaScript Semicolon Insertion: Everything you need to know |date=28 May 2010 |archive-url=https://web.archive.org/web/20171002224530/http://inimino.org/~inimino/blog/javascript_semicolons |archive-date=2 October 2017 |dead-url-status=nolive}}</ref><ref>{{cite web |url=https://mislav.net/2010/05/semicolons/ |title=Semicolons in JavaScript are optional |first=Mislav |last=Marohnić |date=7 May 2010 |archive-url=https://web.archive.org/web/20170808231150/https://mislav.net/2010/05/semicolons/ |archive-date=8 August 2017 |dead-url-status=nolive}}</ref> For example:
<syntaxhighlight lang="JavaScript">
a = b + c
Line 40 ⟶ 35:
...to avoid being parsed as <code>c()</code>.
 
== Examples ==
The key to understanding design patterns such as immediately-invoked function expressionsIIFE is to realize that untilprior recentlyto ES6, JavaScript had only featured [[Scope (computer science)#Function scope|function scope]] (butthus notlacking [[Scope (computer science)#Block scope|block scope]]), and passespassing [[Call_by_reference|values by reference]] inside a [[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 entirelythe truecase, inas the latestES6 version of JavaScript implements block scoping is available and becomes evident when using the new <code>let</code> and <code>const</code> keywords.<ref>ECMAScript{{cite 6:web New|last1=Orendorff Features|first1=Jason |title=ES6 In Depth: Overviewlet &and Comparison,const [http|url=https://es6-featureshacks.mozilla.org/#BlockScopedVariables Block2015/07/es6-Scopedin-depth-let-and-const/ Variables|website=Mozilla Hacks – the Web developer blog |publisher=[[Mozilla]] |access-date=16 October 2024 |date=31 Jul 2015}}</ref><syntaxhighlight lang="javascript">
// 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="JavaScriptjavascript">
varlet v, getValue;
v = 1;
getValue = function () { return v; };
Line 56 ⟶ 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 |lastlast1=Otero |firstfirst1=Cesar |last2=Larsen |first2=Rob |title=Professional jQuery |year=2012 |publisher=John Wiley & Sons |isbn=978-1-118-22211-9 |page=31}}</ref>
 
<syntaxhighlight lang="JavaScriptjavascript">
varlet v, getValue;
v = 1;
getValue = (function (x) {
Line 70 ⟶ 84:
 
This is equivalent to the following code:
<syntaxhighlight lang="JavaScriptjavascript">
varlet v, getValue;
v = 1;
function f(x) {
Line 81 ⟶ 95:
getValue(); // 1
</syntaxhighlight>
 
David Herman's ''Effective JavaScript'' contains an example illustrating the problems of evaluation context inside loops.<ref>{{cite book |last=Herman |first=David |title=Effective Javascript |year=2012 |publisher=Addison-Wesley |isbn=978-0-321-81218-6 |pages=44–45}}</ref> While Herman's example is deliberately convoluted, it arises directly from the same lack of block scope.<ref>{{cite book |last=Zakas |first=Nicholas C. |title=Professional JavaScript for Web Developers |chapter=Mimicking Block Scope |year=2011 |publisher=John Wiley & Sons |isbn=978-1-118-23309-2}}</ref>
 
=== 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="JavaScriptjavascript">
// "counter" is a function that returns an object with properties, which in this case are functions.
varlet counter = (function () {
varlet i = 0;
 
return {
Line 115 ⟶ 127:
 
== Terminology ==
Originally known as a "self-executing anonymous function",<ref>{{cite book |last=Resig |first=John |title=Pro JavaScript Techniques |year=2006 |publisher=Apress |isbn=978-1-4302-0283-7 |page=29}}</ref> Ben Alman later introduced the current term IIFE as a more semantically accurate name 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=978-1-4493-3487-1 |page=206}}</ref><ref>{{cite news |last=Baagoe |first=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 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]]{{nbsp}}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/>
 
"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/> HoweverNotably, immediately- invoked functions doneed not need to be anonymous inherently, and [[ECMAScript]]{{nbsp}}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> makingrendering the latteroriginal term lessa accurate[[misnomer]].<ref name=Osmani/><ref name=JQ/>
In [[lambda calculus]], this construct was referred to as "redex", for reducible expression, see [[Reduction strategy (code optimization)|Reduction strategy]].
 
== See also ==
*[[Evaluation strategy]]
 
== References ==
Line 124 ⟶ 139:
== External links ==
* {{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}}
* {{cite web |last=Soshnikov |first=Dmitry |title=ECMA-262-3 in detail. Chapter&nbsp;5. Functions. |url=http://dmitrysoshnikov.com/ecmascript/chapter-5-functions/#question-about-surrounding-parentheses |accessdate=4 February 2013 |archive-url=https://web.archive.org/web/20171201032007/http://dmitrysoshnikov.com/ecmascript/chapter-5-functions/#question-about-surrounding-parentheses |archive-date=1 December 2017 |dead-url=no}}
 
[[Category:JavaScript]]
[[Category:Programming language concepts]]