Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p><strong>Editor's Note:</strong> All functions in JavaScript are closures as explained in this <a href="http://javascriptweblog.wordpress.com/2010/10/25/understanding-javascript-closures/" rel="noreferrer" title="Understanding JavaScript Closures | JavaScript, JavaScript&#8230;">post</a>. However we are only interested in identifying a subset of these functions which are <a href="https://developer.mozilla.org/en-US/docs/JavaScript/Guide/Closures" rel="noreferrer" title="Closures - JavaScript | MDN">interesting</a> from a theoretical point of view. Henceforth any reference to the word <em>closure</em> will refer to this subset of functions unless otherwise stated.</p> <p>A simple explanation for closures:</p> <ol> <li>Take a function. Let's call it F.</li> <li>List all the variables of F.</li> <li>The variables may be of two types: <ol> <li>Local variables (bound variables)</li> <li>Non-local variables (free variables)</li> </ol></li> <li>If F has no free variables then it cannot be a closure.</li> <li>If F has any free variables (which are defined in <strong>a</strong> parent scope of F) then: <ol> <li>There must be only one parent scope of F to which <strong>a</strong> free variable is bound.</li> <li>If F is <strong>referenced</strong> from outside <strong>that</strong> parent scope, then it becomes a closure for <strong>that</strong> free variable.</li> <li><strong>That</strong> free variable is called an upvalue of the closure F.</li> </ol></li> </ol> <p>Now let's use this to figure out who uses closures and who doesn't (for the sake of explanation I have named the functions):</p> <p><strong>Case 1: Your Friend's Program</strong></p> <pre><code>for (var i = 0; i &lt; 10; i++) { (function f() { var i2 = i; setTimeout(function g() { console.log(i2); }, 1000); })(); } </code></pre> <p>In the above program there are two functions: <code>f</code> and <code>g</code>. Let's see if they are closures:</p> <p>For <code>f</code>:</p> <ol> <li>List the variables: <ol> <li><code>i2</code> is a <strong>local</strong> variable.</li> <li><code>i</code> is a <strong>free</strong> variable.</li> <li><code>setTimeout</code> is a <strong>free</strong> variable.</li> <li><code>g</code> is a <strong>local</strong> variable.</li> <li><code>console</code> is a <strong>free</strong> variable.</li> </ol></li> <li>Find the parent scope to which each free variable is bound: <ol> <li><code>i</code> is <strong>bound</strong> to the global scope.</li> <li><code>setTimeout</code> is <strong>bound</strong> to the global scope.</li> <li><code>console</code> is <strong>bound</strong> to the global scope.</li> </ol></li> <li>In which scope is the function <strong>referenced</strong>? The <strong>global scope</strong>. <ol> <li>Hence <code>i</code> is not <strong>closed over</strong> by <code>f</code>.</li> <li>Hence <code>setTimeout</code> is not <strong>closed over</strong> by <code>f</code>.</li> <li>Hence <code>console</code> is not <strong>closed over</strong> by <code>f</code>.</li> </ol></li> </ol> <p>Thus the function <code>f</code> is not a closure.</p> <p>For <code>g</code>:</p> <ol> <li>List the variables: <ol> <li><code>console</code> is a <strong>free</strong> variable.</li> <li><code>i2</code> is a <strong>free</strong> variable.</li> </ol></li> <li>Find the parent scope to which each free variable is bound: <ol> <li><code>console</code> is <strong>bound</strong> to the global scope.</li> <li><code>i2</code> is <strong>bound</strong> to the scope of <code>f</code>.</li> </ol></li> <li>In which scope is the function <strong>referenced</strong>? The <strong>scope of <code>setTimeout</code></strong>. <ol> <li>Hence <code>console</code> is not <strong>closed over</strong> by <code>g</code>.</li> <li>Hence <code>i2</code> is <strong>closed over</strong> by <code>g</code>.</li> </ol></li> </ol> <p>Thus the function <code>g</code> is a closure for the free variable <code>i2</code> (which is an upvalue for <code>g</code>) <strong>when</strong> it's <strong>referenced</strong> from within <code>setTimeout</code>.</p> <p><em>Bad for you:</em> Your friend is using a closure. The inner function is a closure.</p> <p><strong>Case 2: Your Program</strong></p> <pre><code>for (var i = 0; i &lt; 10; i++) { setTimeout((function f(i2) { return function g() { console.log(i2); }; })(i), 1000); } </code></pre> <p>In the above program there are two functions: <code>f</code> and <code>g</code>. Let's see if they are closures:</p> <p>For <code>f</code>:</p> <ol> <li>List the variables: <ol> <li><code>i2</code> is a <strong>local</strong> variable.</li> <li><code>g</code> is a <strong>local</strong> variable.</li> <li><code>console</code> is a <strong>free</strong> variable.</li> </ol></li> <li>Find the parent scope to which each free variable is bound: <ol> <li><code>console</code> is <strong>bound</strong> to the global scope.</li> </ol></li> <li>In which scope is the function <strong>referenced</strong>? The <strong>global scope</strong>. <ol> <li>Hence <code>console</code> is not <strong>closed over</strong> by <code>f</code>.</li> </ol></li> </ol> <p>Thus the function <code>f</code> is not a closure.</p> <p>For <code>g</code>:</p> <ol> <li>List the variables: <ol> <li><code>console</code> is a <strong>free</strong> variable.</li> <li><code>i2</code> is a <strong>free</strong> variable.</li> </ol></li> <li>Find the parent scope to which each free variable is bound: <ol> <li><code>console</code> is <strong>bound</strong> to the global scope.</li> <li><code>i2</code> is <strong>bound</strong> to the scope of <code>f</code>.</li> </ol></li> <li>In which scope is the function <strong>referenced</strong>? The <strong>scope of <code>setTimeout</code></strong>. <ol> <li>Hence <code>console</code> is not <strong>closed over</strong> by <code>g</code>.</li> <li>Hence <code>i2</code> is <strong>closed over</strong> by <code>g</code>.</li> </ol></li> </ol> <p>Thus the function <code>g</code> is a closure for the free variable <code>i2</code> (which is an upvalue for <code>g</code>) <strong>when</strong> it's <strong>referenced</strong> from within <code>setTimeout</code>.</p> <p><em>Good for you:</em> You are using a closure. The inner function is a closure.</p> <p>So both you and your friend are using closures. Stop arguing. I hope I cleared the concept of closures and how to identify them for the both of you.</p> <p><strong>Edit:</strong> A simple explanation as to why are all functions closures (credits @Peter):</p> <p>First let's consider the following program (it's the <a href="http://jsfiddle.net/KyQKw/" rel="noreferrer">control</a>):</p> <p><div class="snippet" data-lang="js" data-hide="false" data-console="false" data-babel="false"> <div class="snippet-code"> <pre class="snippet-code-js lang-js prettyprint-override"><code>lexicalScope(); function lexicalScope() { var message = "This is the control. You should be able to see this message being alerted."; regularFunction(); function regularFunction() { alert(eval("message")); } }</code></pre> </div> </div> </p> <ol> <li>We know that both <code>lexicalScope</code> and <code>regularFunction</code> aren't closures <strong>from the above definition</strong>.</li> <li>When we execute the program <strong>we expect</strong> <code>message</code> to be alerted <strong>because</strong> <code>regularFunction</code> is not a closure (i.e. it has access to <strong>all</strong> the variables in its parent scope - including <code>message</code>).</li> <li>When we execute the program <strong>we observe</strong> that <code>message</code> is indeed alerted.</li> </ol> <p>Next let's consider the following program (it's the <a href="http://jsfiddle.net/KyQKw/1/" rel="noreferrer">alternative</a>):</p> <p><div class="snippet" data-lang="js" data-hide="false" data-console="false" data-babel="false"> <div class="snippet-code"> <pre class="snippet-code-js lang-js prettyprint-override"><code>var closureFunction = lexicalScope(); closureFunction(); function lexicalScope() { var message = "This is the alternative. If you see this message being alerted then in means that every function in JavaScript is a closure."; return function closureFunction() { alert(eval("message")); }; }</code></pre> </div> </div> </p> <ol> <li>We know that only <code>closureFunction</code> is a closure <strong>from the above definition</strong>.</li> <li>When we execute the program <strong>we expect</strong> <code>message</code> not to be alerted <strong>because</strong> <code>closureFunction</code> is a closure (i.e. it only has access to all its <strong>non-local variables</strong> at <strong>the time the function is created</strong> (<a href="https://stackoverflow.com/a/12930799/783743" title="scope - JavaScript closures vs. anonymous functions - Stack Overflow">see this answer</a>) - this does not include <code>message</code>).</li> <li>When we execute the program <strong>we observe</strong> that <code>message</code> is actually being alerted.</li> </ol> <p>What do we infer from this?</p> <ol> <li>JavaScript interpreters do not treat closures differently from the way they treat other functions.</li> <li>Every function carries its <a href="http://dmitrysoshnikov.com/ecmascript/chapter-4-scope-chain/" rel="noreferrer" title="ECMA-262 &raquo; ECMA-262-3 in detail. Chapter 4. Scope chain.">scope chain</a> along with it. Closures don't have a <strong>separate</strong> referencing environment.</li> <li>A closure is just like every other function. We just call them closures when they are <strong>referenced</strong> in a scope <strong>outside</strong> the scope to which they belong <strong>because</strong> this is an interesting case.</li> </ol>
 

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