Immediately invoked function expression: Difference between revisions

Content deleted Content added
Examples: clarify
Citations to templates; futureproof citations; citations outside punctuation; harmonize dates, spacing; format ISBNs
Line 1:
 
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 |yeardate=15 November 2010 |accessdate=4 February 2013 |archive-url=https://web.archive.org/web/20171201033208/http://benalman.com/news/2010/11/immediately-invoked-function-expression/ |archive-date=1 December 2017 |dead-url=no}}</ref>) is a [[JavaScript]] [[Programming_idiomProgramming 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_hoistingScoping 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=9781430202837978-1-4302-0283-7 |pagespage=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=9781449334871978-1-4493-3487-1 |pagespage=206}}</ref><ref>{{cite news |last1last=Baagoe |first1first=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>
 
== 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=9781449342883978-1-4493-4288-3 |pagespage=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 |publisher=Mozilla Developer Network}}</ref> i.e. in parentheses, to explicitly 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=9781449327682978-1-4493-2768-2 |pagespage=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 () { /* ... */ })();
Line 31:
</syntaxhighlight>
 
An initial parenthesis is one case where the automatic [[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]", Friday,|date=28 May 28, 2010 |archive-url=https://web.archive.org/web/20171002224530/http://inimino.org/~inimino/blog/javascript_semicolons |archive-date=2 October 2017 |dead-url=no}}</ref><ref>"[http{{cite web |url=https://mislav.uniqpath.comnet/2010/05/semicolons/ |title=Semicolons in JavaScript are optional]", by |first=Mislav |last=Marohnić, 07|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=no}}</ref> For example:
<syntaxhighlight lang="JavaScript">
a = b + c
Line 38:
})();
</syntaxhighlight>
…to...to avoid being parsed as <code>c()</code>.
 
== Examples ==
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=9781593272821978-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>.)
 
=== 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">
var v, getValue;
Line 50:
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 |last=Otero |first=Cesar |last2=Larsen |first2=Rob |title=Professional jQuery |year=2012 |publisher=John Wiley & Sons |isbn=9781118222119978-1-118-22211-9 |pagespage=31}}</ref>
 
<syntaxhighlight lang="JavaScript">
Line 82:
</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=9780321812186978-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=9781118233092978-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=9781118301333978-1-118-30133-3 |pagespage=145}}</ref> The following example comes from Alman's post on IIFEs.<ref name=Alman />
 
<syntaxhighlight lang="JavaScript">
Line 106:
 
// These calls access the function properties returned by "counter".
counter.get(); // 0
counter.set(3);
counter.increment(); // 4
counter.increment(); // 5
</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]] {{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 />
 
In [[lambda calculus]], this construct was referred to as "redex", for reducible expression, see [[Reduction strategy (code optimization)|Reduction strategy]].
 
== References ==
{{reflist|30em}}
 
== 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]]