Immediately invoked function expression: Difference between revisions

Content deleted Content added
Tag: references removed
MOD31P (talk | contribs)
m Added additional way to pass variables into IIFE
 
(41 intermediate revisions by 29 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]]ECMAScript from within blocks, protect against polluting the [[Global 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>
 
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 [[JavaScript syntax#Scoping and hoisting|variable hoisting]] from within blocks, protectprotecting against polluting the [[Global variable|global environment]] and simultaneously allowallowing public access to methods while retaining privacy for variables defined within the function. ThisIn conceptother haswords, beenit referredwraps tofunctions asand a self-executing anonymous functionvariables,[2] butkeeping Benthem Almanout introducedof the termglobal IIFEscope asand agiving morethem semanticallya accuratelocal term for the idiom, shortly after its discussion arose on comp.lang.javascriptscope.
 
== ExamplesUsage ==
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>
The key to understanding design patterns such as immediately invoked function expressions is to realize that until recently JavaScript had only [[Scope (computer science)#Function scope|function scope]] (but not [[Scope (computer science)#Block scope|block scope]]) and passes values by reference inside a [[Closure (computer science)|closure]].<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 entirely true, in the latest version of JavaScript block scoping is available and becomes evident when using the new <code>let</code> and <code>const</code> keywords.<ref>ECMAScript 6: New Features: Overview & Comparison, [http://es6-features.org/#BlockScopedVariables Block-Scoped Variables]</ref>
<syntaxhighlight lang="JavaScript">
(function () { /* ... */ })();
(function () { /* ... */ }());
(() => { /* ... */ })(); // With ES6 arrow functions (though parentheses only allowed on outside)
</syntaxhighlight>
 
In contexts where an expression is expected, wrapping in parentheses is not necessary:
=== Evaluation context ===
<syntaxhighlight lang="javascript">
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 f = function () { /* ... */ }();
true && function () { /* ... */ }();
0, function () { /* ... */ }();
</syntaxhighlight>
 
Passing variables into the scope is done as follows:
<syntaxhighlight lang="javascript">
(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 |url-status=live}}</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 |url-status=live}}</ref> For example:
<syntaxhighlight lang="JavaScript">
a = b + c
var v, getValue;
;(function () {
// code
})();
</syntaxhighlight>
...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="javascript">
varlet v, getValue;
v = 1;
getValue = function () { return v; };
Line 20 ⟶ 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 34 ⟶ 84:
 
This is equivalent to the following code:
<syntaxhighlight lang="JavaScriptjavascript">
varlet v, getValue;
v = 1;
function f(x) {
Line 45 ⟶ 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 79 ⟶ 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 88 ⟶ 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]]