Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<h1>JavaScript closures for beginners</h1> <blockquote>Submitted by Morris on Tue, 2006-02-21 10:19. Community-edited since.</blockquote> <h2>Closures are not magic</h2> <p>This page explains closures so that a programmer can understand them &mdash; using working JavaScript code. It is not for gurus or functional programmers.</p> <p>Closures are <em>not hard</em> to understand once the core concept is grokked. However, they are impossible to understand by reading any theoretical or academically oriented explanations!</p> <p>This article is intended for programmers with some programming experience in a mainstream language, and who can read the following JavaScript function:</p> <p><div class="snippet" data-lang="js" data-hide="false" data-console="true" data-babel="false"> <div class="snippet-code"> <pre class="snippet-code-js lang-js prettyprint-override"><code>function sayHello(name) { var text = 'Hello ' + name; var say = function() { console.log(text); } say(); } sayHello('Joe');</code></pre> </div> </div> </p> <h2>Two brief summaries</h2> <ul> <li><p>When a function (foo) declares other functions (bar and baz), the family of local variables created in foo is <em>not destroyed</em> when the function exits. The variables merely become invisible to the outside world. foo can therefore cunningly return the functions bar and baz, and they can continue to read, write and communicate with each other through this closed-off family of variables ("the closure") that nobody else can meddle with, not even someone who calls foo again in future.</p></li> <li><p>A closure is one way of supporting <a href="https://en.wikipedia.org/wiki/First-class_function" rel="noreferrer">first-class functions</a>; it is an expression that can reference variables within its scope (when it was first declared), be assigned to a variable, be passed as an argument to a function, or be returned as a function result. </p></li> </ul> <h2>An example of a closure</h2> <p>The following code returns a reference to a function:</p> <p><div class="snippet" data-lang="js" data-hide="false" data-console="true" data-babel="false"> <div class="snippet-code"> <pre class="snippet-code-js lang-js prettyprint-override"><code>function sayHello2(name) { var text = 'Hello ' + name; // Local variable var say = function() { console.log(text); } return say; } var say2 = sayHello2('Bob'); say2(); // logs "Hello Bob"</code></pre> </div> </div> </p> <p>Most JavaScript programmers will understand how a reference to a function is returned to a variable (<code>say2</code>) in the above code. If you don't, then you need to look at that before you can learn closures. A programmer using C would think of the function as returning a pointer to a function, and that the variables <code>say</code> and <code>say2</code> were each a pointer to a function.</p> <p>There is a critical difference between a C pointer to a function and a JavaScript reference to a function. In JavaScript, you can think of a function reference variable as having both a pointer to a function <em>as well</em> as a hidden pointer to a closure.</p> <p>The above code has a closure because the anonymous function <code>function() { console.log(text); }</code> is declared <em>inside</em> another function, <code>sayHello2()</code> in this example. In JavaScript, if you use the <code>function</code> keyword inside another function, you are creating a closure.</p> <p>In C and most other common languages, <em>after</em> a function returns, all the local variables are no longer accessible because the stack-frame is destroyed.</p> <p>In JavaScript, if you declare a function within another function, then the local variables of the outer function can remain accessible after returning from it. This is demonstrated above, because we call the function <code>say2()</code> after we have returned from <code>sayHello2()</code>. Notice that the code that we call references the variable <code>text</code>, which was a <em>local variable</em> of the function <code>sayHello2()</code>.</p> <pre><code>function() { console.log(text); } // Output of say2.toString(); </code></pre> <p>Looking at the output of <code>say2.toString()</code>, we can see that the code refers to the variable <code>text</code>. The anonymous function can reference <code>text</code> which holds the value <code>'Hello Bob'</code> because the local variables of <code>sayHello2()</code> have been secretly kept alive in a closure.</p> <p>The genius is that in JavaScript a function reference also has a secret reference to the closure it was created in &mdash; similar to how delegates are a method pointer plus a secret reference to an object.</p> <h2>More examples</h2> <p>For some reason, closures seem really hard to understand when you read about them, but when you see some examples it becomes clear how they work (it took me a while). I recommend working through the examples carefully until you understand how they work. If you start using closures without fully understanding how they work, you would soon create some very weird bugs!</p> <h3>Example 3</h3> <p>This example shows that the local variables are not copied &mdash; they are kept by reference. It is as though the stack-frame stays alive in memory even after the outer function exits!</p> <p><div class="snippet" data-lang="js" data-hide="false" data-console="true" data-babel="false"> <div class="snippet-code"> <pre class="snippet-code-js lang-js prettyprint-override"><code>function say667() { // Local variable that ends up within closure var num = 42; var say = function() { console.log(num); } num++; return say; } var sayNumber = say667(); sayNumber(); // logs 43</code></pre> </div> </div> </p> <h3>Example 4</h3> <p>All three global functions have a common reference to the <em>same</em> closure because they are all declared within a single call to <code>setupSomeGlobals()</code>.</p> <p><div class="snippet" data-lang="js" data-hide="false" data-console="true" data-babel="false"> <div class="snippet-code"> <pre class="snippet-code-js lang-js prettyprint-override"><code>var gLogNumber, gIncreaseNumber, gSetNumber; function setupSomeGlobals() { // Local variable that ends up within closure var num = 42; // Store some references to functions as global variables gLogNumber = function() { console.log(num); } gIncreaseNumber = function() { num++; } gSetNumber = function(x) { num = x; } } setupSomeGlobals(); gIncreaseNumber(); gLogNumber(); // 43 gSetNumber(5); gLogNumber(); // 5 var oldLog = gLogNumber; setupSomeGlobals(); gLogNumber(); // 42 oldLog() // 5</code></pre> </div> </div> </p> <p>The three functions have shared access to the same closure &mdash; the local variables of <code>setupSomeGlobals()</code> when the three functions were defined.</p> <p>Note that in the above example, if you call <code>setupSomeGlobals()</code> again, then a new closure (stack-frame!) is created. The old <code>gLogNumber</code>, <code>gIncreaseNumber</code>, <code>gSetNumber</code> variables are overwritten with <em>new</em> functions that have the new closure. (In JavaScript, whenever you declare a function inside another function, the inside function(s) is/are recreated again <em>each</em> time the outside function is called.)</p> <h3>Example 5</h3> <p>This example shows that the closure contains any local variables that were declared inside the outer function before it exited. Note that the variable <code>alice</code> is actually declared after the anonymous function. The anonymous function is declared first; and when that function is called it can access the <code>alice</code> variable because <code>alice</code> is in the same scope (JavaScript does <a href="https://stackoverflow.com/a/3725763/1269037">variable hoisting</a>). Also <code>sayAlice()()</code> just directly calls the function reference returned from <code>sayAlice()</code> &mdash; it is exactly the same as what was done previously but without the temporary variable.</p> <p><div class="snippet" data-lang="js" data-hide="false" data-console="true" data-babel="false"> <div class="snippet-code"> <pre class="snippet-code-js lang-js prettyprint-override"><code>function sayAlice() { var say = function() { console.log(alice); } // Local variable that ends up within closure var alice = 'Hello Alice'; return say; } sayAlice()();// logs "Hello Alice"</code></pre> </div> </div> </p> <p>Tricky: note also that the <code>say</code> variable is also inside the closure, and could be accessed by any other function that might be declared within <code>sayAlice()</code>, or it could be accessed recursively within the inside function.</p> <h3>Example 6</h3> <p>This one is a real gotcha for many people, so you need to understand it. Be very careful if you are defining a function within a loop: the local variables from the closure may not act as you might first think. </p> <p>You need to understand the "variable hoisting" feature in Javascript in order to understand this example.</p> <p><div class="snippet" data-lang="js" data-hide="false" data-console="true" data-babel="false"> <div class="snippet-code"> <pre class="snippet-code-js lang-js prettyprint-override"><code>function buildList(list) { var result = []; for (var i = 0; i &lt; list.length; i++) { var item = 'item' + i; result.push( function() {console.log(item + ' ' + list[i])} ); } return result; } function testList() { var fnlist = buildList([1,2,3]); // Using j only to help prevent confusion -- could use i. for (var j = 0; j &lt; fnlist.length; j++) { fnlist[j](); } } testList() //logs "item2 undefined" 3 times</code></pre> </div> </div> </p> <p>The line <code>result.push( function() {console.log(item + ' ' + list[i])}</code> adds a reference to an anonymous function three times to the result array. If you are not so familiar with anonymous functions think of it like:</p> <pre><code>pointer = function() {console.log(item + ' ' + list[i])}; result.push(pointer); </code></pre> <p>Note that when you run the example, <code>"item2 undefined"</code> is logged three times! This is because just like previous examples, there is only one closure for the local variables for <code>buildList</code> (which are <code>result</code>, <code>i</code> and <code>item</code>). When the anonymous functions are called on the line <code>fnlist[j]()</code>; they all use the same single closure, and they use the current value for <code>i</code> and <code>item</code> within that one closure (where <code>i</code> has a value of <code>3</code> because the loop had completed, and <code>item</code> has a value of <code>'item2'</code>). Note we are indexing from 0 hence <code>item</code> has a value of <code>item2</code>. And the i++ will increment <code>i</code> to the value <code>3</code>.</p> <p>It may be helpful to see what happens when a block-level declaration of the variable <code>item</code> is used (via the <code>let</code> keyword) instead of a function-scoped variable declaration via the <code>var</code> keyword. If that change is made, then each anonymous function in the array <code>result</code> has its own closure; when the example is run the output is as follows:</p> <pre><code>item0 undefined item1 undefined item2 undefined </code></pre> <p>If the variable <code>i</code> is also defined using <code>let</code> instead of <code>var</code>, then the output is:</p> <pre><code>item0 1 item1 2 item2 3 </code></pre> <h3>Example 7</h3> <p>In this final example, each call to the main function creates a separate closure.</p> <p><div class="snippet" data-lang="js" data-hide="false" data-console="true" data-babel="false"> <div class="snippet-code"> <pre class="snippet-code-js lang-js prettyprint-override"><code>function newClosure(someNum, someRef) { // Local variables that end up within closure var num = someNum; var anArray = [1,2,3]; var ref = someRef; return function(x) { num += x; anArray.push(num); console.log('num: ' + num + '; anArray: ' + anArray.toString() + '; ref.someVar: ' + ref.someVar + ';'); } } obj = {someVar: 4}; fn1 = newClosure(4, obj); fn2 = newClosure(5, obj); fn1(1); // num: 5; anArray: 1,2,3,5; ref.someVar: 4; fn2(1); // num: 6; anArray: 1,2,3,6; ref.someVar: 4; obj.someVar++; fn1(2); // num: 7; anArray: 1,2,3,5,7; ref.someVar: 5; fn2(2); // num: 8; anArray: 1,2,3,6,8; ref.someVar: 5;</code></pre> </div> </div> </p> <h2>Summary</h2> <p>If everything seems completely unclear then the best thing to do is to play with the examples. Reading an explanation is much harder than understanding examples. My explanations of closures and stack-frames, etc. are not technically correct &mdash; they are gross simplifications intended to help to understand. Once the basic idea is grokked, you can pick up the details later.</p> <h2>Final points:</h2> <ul> <li>Whenever you use <code>function</code> inside another function, a closure is used.</li> <li>Whenever you use <code>eval()</code> inside a function, a closure is used. The text you <code>eval</code> can reference local variables of the function, and within <code>eval</code> you can even create new local variables by using <code>eval('var foo = …')</code></li> <li>When you use <code>new Function(…)</code> (the <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function" rel="noreferrer">Function constructor</a>) inside a function, it does not create a closure. (The new function cannot reference the local variables of the outer function.)</li> <li>A closure in JavaScript is like keeping a copy of all the local variables, just as they were when a function exited.</li> <li>It is probably best to think that a closure is always created just an entry to a function, and the local variables are added to that closure.</li> <li>A new set of local variables is kept every time a function with a closure is called (given that the function contains a function declaration inside it, and a reference to that inside function is either returned or an external reference is kept for it in some way).</li> <li>Two functions might look like they have the same source text, but have completely different behavior because of their 'hidden' closure. I don't think JavaScript code can actually find out if a function reference has a closure or not.</li> <li>If you are trying to do any dynamic source code modifications (for example: <code>myFunction = Function(myFunction.toString().replace(/Hello/,'Hola'));</code>), it won't work if <code>myFunction</code> is a closure (of course, you would never even think of doing source code string substitution at runtime, but...).</li> <li>It is possible to get function declarations within function declarations within functions &mdash; and you can get closures at more than one level.</li> <li>I think normally a closure is a term for both the function along with the variables that are captured. Note that I do not use that definition in this article!</li> <li>I suspect that closures in JavaScript differ from those normally found in functional languages.</li> </ul> <h2>Links</h2> <ul> <li>Douglas Crockford's simulated <a href="http://www.crockford.com/javascript/private.html" rel="noreferrer">private attributes and private methods</a> for an object, using closures.</li> <li>A great explanation of how closures can <a href="https://www.codeproject.com/Articles/12231/Memory-Leakage-in-Internet-Explorer-revisited" rel="noreferrer">cause memory leaks in IE</a> if you are not careful.</li> </ul> <h2>Thanks</h2> <p>If you have <em>just</em> learned closures (here or elsewhere!), then I am interested in any feedback from you about any changes you might suggest that could make this article clearer. Send an email to morrisjohns.com (morris_closure @). Please note that I am not a guru on JavaScript &mdash; nor on closures.</p> <hr> <p>Original post by Morris can be found in the <a href="http://web.archive.org/web/20080209105120/http:/blog.morrisjohns.com/javascript_closures_for_dummies" rel="noreferrer">Internet Archive</a>.</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload