{"id":"l-js-2-4","courseId":"javascript-fundamentals","lang":"en","kind":"lesson","summary":"Predict where a variable can be used (block, function and global scope), avoid the old var pitfalls, and use closures to give functions private, remembered state such as an id counter.","html":"<p>Every expense in Pocket needs a unique id so you can edit or delete exactly that one later. The obvious approach is a counter at the top of the file:</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"js\" data-index=\"0\"><div class=\"code-head\"><span class=\"code-title\">JavaScript</span><span class=\"code-actions\"><button type=\"button\" class=\"code-btn\" data-action=\"copy\" aria-label=\"Copy code\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\"/><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"/></svg><span>Copy</span></button></span></div><pre class=\"shiki\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">let</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> nextId </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> 1</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">;</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">function</span><span style=\"color:#8250DF;--shiki-dark:#D2A8FF\"> createId</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">() {</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">  return</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> `exp-${</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">nextId</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">++</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">}`</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">;</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">}</span></span></code></pre></div>\n<p>It works, until some other part of the program, perhaps a “reset” feature written months later, sets <code dir=\"ltr\">nextId = 1</code> again and you get two expenses called <code dir=\"ltr\">exp-1</code>. The counter is visible everywhere, so anything can break it. To protect it you need to understand <strong>scope</strong>: the rules for where a name can be seen.</p>\n<h2 id=\"sec-1\" tabindex=\"-1\">Blocks, functions and the global scope</h2>\n<p>Every pair of curly braces creates a <strong>block</strong>, and <code dir=\"ltr\">let</code> and <code dir=\"ltr\">const</code> names live in the block where they are declared. Functions create a scope too. Names declared outside every block and function are in the <strong>global scope</strong>, visible everywhere.</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"js\" data-run=\"js\" data-index=\"1\"><div class=\"code-head\"><span class=\"code-title\">JavaScript</span><span class=\"code-actions\"><button type=\"button\" class=\"code-btn code-run\" data-action=\"run\" data-lang=\"js\" data-index=\"1\" aria-label=\"Run this example\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><path d=\"M5 5a2 2 0 0 1 3.008-1.728l11.997 6.998a2 2 0 0 1 .003 3.458l-12 7A2 2 0 0 1 5 19z\"/></svg><span>Run</span></button><button type=\"button\" class=\"code-btn\" data-action=\"copy\" aria-label=\"Copy code\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\"/><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"/></svg><span>Copy</span></button></span></div><pre class=\"shiki\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">const</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> appName</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\"> =</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> \"Pocket\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">;           </span><span style=\"color:#6E7781;--shiki-dark:#8B949E\">// global</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">function</span><span style=\"color:#8250DF;--shiki-dark:#D2A8FF\"> describe</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#953800;--shiki-dark:#FFA657\">amount</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">) {</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">  const</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> size</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\"> =</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> amount </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">></span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> 10000</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\"> ?</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> \"big\"</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\"> :</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> \"small\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">;   </span><span style=\"color:#6E7781;--shiki-dark:#8B949E\">// function scope</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">  if</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> (size </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">===</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> \"big\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">) {</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">    const</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> warning</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\"> =</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> \"Think twice\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">;  </span><span style=\"color:#6E7781;--shiki-dark:#8B949E\">// block scope</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">    console.</span><span style=\"color:#8250DF;--shiki-dark:#D2A8FF\">log</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(appName, size, warning);</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">  }</span></span>\n<span class=\"line\"><span style=\"color:#6E7781;--shiki-dark:#8B949E\">  // console.log(warning) here would throw a ReferenceError</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">}</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color:#8250DF;--shiki-dark:#D2A8FF\">describe</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">12000</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">);</span></span></code></pre><div class=\"run-output\" data-run-output=\"1\" hidden></div></div>\n<p>When the engine meets a name, it looks in the current scope first. If the name is not there, it looks in the enclosing scope, then the one around that, out to the global scope. If it still has not found it, you get <code dir=\"ltr\">ReferenceError: … is not defined</code>. The lookup only goes <strong>outward</strong>: code inside a function can read the global <code dir=\"ltr\">appName</code>, but code outside the function can never see <code dir=\"ltr\">size</code>.</p>\n<p>That is why the <code dir=\"ltr\">warning</code> line is commented out. The block that declared <code dir=\"ltr\">warning</code> has ended, so the name is gone.</p>\n<figure class=\"diagram\"><svg class=\"diagram-svg\" focusable=\"false\" viewBox=\"0 0 640 250\" role=\"img\" aria-labelledby=\"l-js-2-4-t1\"><defs><marker id=\"arrow-l-js-2-4-1\" viewBox=\"0 0 10 10\" refX=\"9\" refY=\"5\" markerWidth=\"7\" markerHeight=\"7\" orient=\"auto-start-reverse\"><path d=\"M0 0 L10 5 L0 10 z\" class=\"d-arrowhead\"/></marker></defs>\n  <title id=\"l-js-2-4-t1\">Three nested boxes: the global scope holds appName, the describe function scope holds amount and size, and the if block holds warning. An arrow from the innermost block points outward to show that lookups go from inner to outer scopes.</title>\n  <rect class=\"d-box\" x=\"20\" y=\"16\" width=\"600\" height=\"220\" rx=\"14\"/>\n  <text class=\"d-label-strong\" x=\"40\" y=\"44\">Global</text>\n  <text class=\"d-code\" x=\"470\" y=\"44\">appName</text>\n  <rect class=\"d-box-accent\" x=\"50\" y=\"62\" width=\"540\" height=\"156\" rx=\"12\"/>\n  <text class=\"d-label-strong\" x=\"70\" y=\"90\">function describe</text>\n  <text class=\"d-code\" x=\"410\" y=\"90\">amount, size</text>\n  <rect class=\"d-box-primary\" x=\"80\" y=\"110\" width=\"300\" height=\"88\" rx=\"10\"/>\n  <text class=\"d-label-strong\" x=\"100\" y=\"138\">if block</text>\n  <text class=\"d-code\" x=\"100\" y=\"172\">warning</text>\n  <path class=\"d-arrow\" d=\"M380 160 L460 160 L460 102\" marker-end=\"url(#arrow-l-js-2-4-1)\"/>\n  <path class=\"d-arrow\" d=\"M470 102 L520 56\" marker-end=\"url(#arrow-l-js-2-4-1)\"/>\n  <text class=\"d-label-muted\" x=\"520\" y=\"170\" text-anchor=\"middle\">look outward</text>\n</svg><figcaption>Scopes nest, and lookups go outward</figcaption></figure>\n<p>If an inner scope declares a name that already exists outside, the inner one <strong>shadows</strong> the outer one: inside the block, the name means the inner variable. It is legal, but two different things with one name make code hard to read, so pick distinct names.</p>\n<h2 id=\"sec-2\" tabindex=\"-1\">The trouble with var</h2>\n<p>Before 2015, JavaScript only had <code dir=\"ltr\">var</code>, and <code dir=\"ltr\">var</code> ignores blocks: it is visible throughout the whole function it is in. That produces one famous bug. Here the loop schedules three functions to run a moment later with <code dir=\"ltr\">setTimeout</code>:</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"js\" data-run=\"js\" data-index=\"2\"><div class=\"code-head\"><span class=\"code-title\">JavaScript</span><span class=\"code-actions\"><button type=\"button\" class=\"code-btn code-run\" data-action=\"run\" data-lang=\"js\" data-index=\"2\" aria-label=\"Run this example\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><path d=\"M5 5a2 2 0 0 1 3.008-1.728l11.997 6.998a2 2 0 0 1 .003 3.458l-12 7A2 2 0 0 1 5 19z\"/></svg><span>Run</span></button><button type=\"button\" class=\"code-btn\" data-action=\"copy\" aria-label=\"Copy code\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\"/><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"/></svg><span>Copy</span></button></span></div><pre class=\"shiki\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">for</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> (</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">var</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> i </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> 0</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">; i </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">&#x3C;</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> 3</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">; i</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">++</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">) {</span></span>\n<span class=\"line\"><span style=\"color:#8250DF;--shiki-dark:#D2A8FF\">  setTimeout</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(() </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=></span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> console.</span><span style=\"color:#8250DF;--shiki-dark:#D2A8FF\">log</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"var:\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, i), </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">0</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">);</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">}</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">for</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> (</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">let</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> j </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> 0</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">; j </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">&#x3C;</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> 3</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">; j</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">++</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">) {</span></span>\n<span class=\"line\"><span style=\"color:#8250DF;--shiki-dark:#D2A8FF\">  setTimeout</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(() </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=></span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> console.</span><span style=\"color:#8250DF;--shiki-dark:#D2A8FF\">log</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"let:\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, j), </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">0</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">);</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">}</span></span></code></pre><div class=\"run-output\" data-run-output=\"2\" hidden></div></div>\n<p>The <code dir=\"ltr\">var</code> loop logs <code dir=\"ltr\">3</code> three times, because there is only one <code dir=\"ltr\">i</code> for the whole loop, and by the time the functions run it has reached 3. The <code dir=\"ltr\">let</code> loop logs 0, 1 and 2, because <code dir=\"ltr\">let</code> creates a fresh <code dir=\"ltr\">j</code> for each pass and each function keeps its own. Those functions remembering variables is exactly what a closure is.</p>\n<aside class=\"callout callout-mistake\" role=\"note\"><p class=\"callout-title\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><path d=\"m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3\"/><path d=\"M12 9v4\"/><path d=\"M12 17h.01\"/></svg><span><span class=\"callout-kind\">Common mistake</span><span class=\"callout-sep\" aria-hidden=\"true\"> · </span>Copying var from old tutorials</span></p>\n<p>Much of the JavaScript on the internet predates <code dir=\"ltr\">let</code> and <code dir=\"ltr\">const</code>. When you copy a snippet that uses <code dir=\"ltr\">var</code>, change it to <code dir=\"ltr\">const</code> (or <code dir=\"ltr\">let</code> if it is reassigned) and check that nothing outside the block was relying on the leak.</p>\n</aside>\n<h2 id=\"sec-3\" tabindex=\"-1\">Closures: functions that remember</h2>\n<p>A function created inside another function can use the outer function’s variables. The surprise is that it keeps that access <strong>after the outer function has returned</strong>:</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"js\" data-run=\"js\" data-index=\"3\"><div class=\"code-head\"><span class=\"code-title\">JavaScript</span><span class=\"code-actions\"><button type=\"button\" class=\"code-btn code-run\" data-action=\"run\" data-lang=\"js\" data-index=\"3\" aria-label=\"Run this example\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><path d=\"M5 5a2 2 0 0 1 3.008-1.728l11.997 6.998a2 2 0 0 1 .003 3.458l-12 7A2 2 0 0 1 5 19z\"/></svg><span>Run</span></button><button type=\"button\" class=\"code-btn\" data-action=\"copy\" aria-label=\"Copy code\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\"/><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"/></svg><span>Copy</span></button></span></div><pre class=\"shiki\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">function</span><span style=\"color:#8250DF;--shiki-dark:#D2A8FF\"> createIdGenerator</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#953800;--shiki-dark:#FFA657\">prefix</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">) {</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">  let</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> count </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> 0</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">;</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">  return</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> () </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=></span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> {</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">    count</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">++</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">;</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">    return</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> `${</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">prefix</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">}-${</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">count</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">}`</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">;</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">  };</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">}</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">const</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> nextExpenseId</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\"> =</span><span style=\"color:#8250DF;--shiki-dark:#D2A8FF\"> createIdGenerator</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"exp\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">);</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">const</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> nextCategoryId</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\"> =</span><span style=\"color:#8250DF;--shiki-dark:#D2A8FF\"> createIdGenerator</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"cat\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">);</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">console.</span><span style=\"color:#8250DF;--shiki-dark:#D2A8FF\">log</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#8250DF;--shiki-dark:#D2A8FF\">nextExpenseId</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">());</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">console.</span><span style=\"color:#8250DF;--shiki-dark:#D2A8FF\">log</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#8250DF;--shiki-dark:#D2A8FF\">nextExpenseId</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">());</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">console.</span><span style=\"color:#8250DF;--shiki-dark:#D2A8FF\">log</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#8250DF;--shiki-dark:#D2A8FF\">nextCategoryId</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">());</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">console.</span><span style=\"color:#8250DF;--shiki-dark:#D2A8FF\">log</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#8250DF;--shiki-dark:#D2A8FF\">nextExpenseId</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">());</span></span></code></pre><div class=\"run-output\" data-run-output=\"3\" hidden></div></div>\n<p>Follow the engine. Calling <code dir=\"ltr\">createIdGenerator(&quot;exp&quot;)</code> creates a fresh <code dir=\"ltr\">prefix</code> and <code dir=\"ltr\">count</code>, builds the arrow function, and returns it. Normally a function’s variables vanish when it returns, but the arrow function still refers to <code dir=\"ltr\">count</code> and <code dir=\"ltr\">prefix</code>, so they stay alive, attached to it. That pairing of a function with the variables it was born next to is a <strong>closure</strong>.</p>\n<p>Each call of <code dir=\"ltr\">createIdGenerator</code> creates a new, separate set of variables. That is why <code dir=\"ltr\">nextCategoryId()</code> starts from 1 and the expense ids carry on from where they were.</p>\n<p>Now look at the safety you gained. There is no global <code dir=\"ltr\">count</code>. No other code can read it, reset it or set it to a duplicate value. The only way to affect it is to call the function you were given, which can only ever move it forward. This is the standard way to give a function <strong>private state</strong> in JavaScript.</p>\n<aside class=\"callout callout-why\" role=\"note\"><p class=\"callout-title\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><circle cx=\"12\" cy=\"12\" r=\"10\"/><circle cx=\"12\" cy=\"12\" r=\"6\"/><circle cx=\"12\" cy=\"12\" r=\"2\"/></svg><span><span class=\"callout-kind\">Why this matters</span><span class=\"callout-sep\" aria-hidden=\"true\"> · </span>Why closures matter so much</span></p>\n<p>You will rarely write the word “closure” in code, but you will use one every day. Every callback that reads a variable from the surrounding code, every click handler in section 4 that updates a list, every function that remembers a setting, is a closure. When something “remembers” a value, this is the mechanism.</p>\n</aside>\n<p>A closure can protect more than a counter. Here is a budget that can only go down through the function you hand out:</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"js\" data-run=\"js\" data-index=\"4\"><div class=\"code-head\"><span class=\"code-title\">JavaScript</span><span class=\"code-actions\"><button type=\"button\" class=\"code-btn code-run\" data-action=\"run\" data-lang=\"js\" data-index=\"4\" aria-label=\"Run this example\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><path d=\"M5 5a2 2 0 0 1 3.008-1.728l11.997 6.998a2 2 0 0 1 .003 3.458l-12 7A2 2 0 0 1 5 19z\"/></svg><span>Run</span></button><button type=\"button\" class=\"code-btn\" data-action=\"copy\" aria-label=\"Copy code\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\"/><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"/></svg><span>Copy</span></button></span></div><pre class=\"shiki\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">function</span><span style=\"color:#8250DF;--shiki-dark:#D2A8FF\"> createBudget</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#953800;--shiki-dark:#FFA657\">limitCents</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">) {</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">  let</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> remaining </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> limitCents;</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">  return</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> (</span><span style=\"color:#953800;--shiki-dark:#FFA657\">spentCents</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">) </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=></span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> {</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">    remaining </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">-=</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> spentCents;</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">    return</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> remaining;</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">  };</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">}</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">const</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> spend</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\"> =</span><span style=\"color:#8250DF;--shiki-dark:#D2A8FF\"> createBudget</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">2000</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">);</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">console.</span><span style=\"color:#8250DF;--shiki-dark:#D2A8FF\">log</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#8250DF;--shiki-dark:#D2A8FF\">spend</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">450</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">));</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">console.</span><span style=\"color:#8250DF;--shiki-dark:#D2A8FF\">log</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#8250DF;--shiki-dark:#D2A8FF\">spend</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">1220</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">));</span></span></code></pre><div class=\"run-output\" data-run-output=\"4\" hidden></div></div>\n<p>Section 2 is complete: you can make decisions, repeat work, and package it in functions with their own private state. Section 3 turns to data, starting with the list you have been looping over: the array.</p>\n","toc":[{"id":"sec-1","text":"Blocks, functions and the global scope","level":2},{"id":"sec-2","text":"The trouble with var","level":2},{"id":"sec-3","text":"Closures: functions that remember","level":2}],"takeaways":["Scope is where a name can be used: <code dir=\"ltr\">let</code> and <code dir=\"ltr\">const</code> live in the nearest block <code dir=\"ltr\">{ }</code>, and lookups go outward, never inward.","An inner name with the same name as an outer one shadows it inside the inner scope, which is legal but easy to misread.","<code dir=\"ltr\">var</code> ignores blocks and is scoped to the whole function, which causes classic bugs; use <code dir=\"ltr\">let</code> and <code dir=\"ltr\">const</code>.","A closure is a function that keeps access to the variables of the scope where it was created, even after that outer function has returned.","Each call of an outer function creates a fresh set of variables, so every closure it returns has its own private state."],"further":[{"title":"Closures (MDN)","url":"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Closures"},{"title":"Scope (MDN glossary)","url":"https://developer.mozilla.org/en-US/docs/Glossary/Scope"},{"title":"var (MDN)","url":"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/var"}],"quiz":[{"q":"<p>What happens when this runs?</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"js\" data-index=\"0\"><div class=\"code-head\"><span class=\"code-title\">JavaScript</span><span class=\"code-actions\"><button type=\"button\" class=\"code-btn\" data-action=\"copy\" aria-label=\"Copy code\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\"/><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"/></svg><span>Copy</span></button></span></div><pre class=\"shiki\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">function</span><span style=\"color:#8250DF;--shiki-dark:#D2A8FF\"> check</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#953800;--shiki-dark:#FFA657\">amount</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">) {</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">  if</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> (amount </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">></span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> 100</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">) {</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">    const</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> label</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\"> =</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> \"big\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">;</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">  }</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">  return</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> label;</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">}</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">console.</span><span style=\"color:#8250DF;--shiki-dark:#D2A8FF\">log</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#8250DF;--shiki-dark:#D2A8FF\">check</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">500</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">));</span></span></code></pre></div>\n","options":[{"text":"It logs <code dir=\"ltr\">big</code>.","why":"<code dir=\"ltr\">label</code> was declared with <code dir=\"ltr\">const</code> inside the <code dir=\"ltr\">if</code> block, so it does not exist outside those braces."},{"text":"It logs <code dir=\"ltr\">undefined</code>.","why":"<code dir=\"ltr\">undefined</code> is what <code dir=\"ltr\">var</code> gives when the <code dir=\"ltr\">if</code> is skipped, as in <code dir=\"ltr\">check(50)</code>; with <code dir=\"ltr\">var</code> and 500 you would even get <code dir=\"ltr\">big</code>. With <code dir=\"ltr\">const</code>, the name does not exist outside its block, so using it there is an error."},{"text":"It throws <code dir=\"ltr\">ReferenceError: label is not defined</code>.","why":"Correct. Block scope means <code dir=\"ltr\">label</code> disappears at the closing brace of the <code dir=\"ltr\">if</code>, and <code dir=\"ltr\">return label</code> cannot see it."}],"answer":2},{"q":"<p>What does this log?</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"js\" data-index=\"1\"><div class=\"code-head\"><span class=\"code-title\">JavaScript</span><span class=\"code-actions\"><button type=\"button\" class=\"code-btn\" data-action=\"copy\" aria-label=\"Copy code\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\"/><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"/></svg><span>Copy</span></button></span></div><pre class=\"shiki\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">function</span><span style=\"color:#8250DF;--shiki-dark:#D2A8FF\"> makeCounter</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">() {</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">  let</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> count </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> 0</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">;</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">  return</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> () </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=></span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> {</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">    count</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">++</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">;</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">    return</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> count;</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">  };</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">}</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">const</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> a</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\"> =</span><span style=\"color:#8250DF;--shiki-dark:#D2A8FF\"> makeCounter</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">();</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">const</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> b</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\"> =</span><span style=\"color:#8250DF;--shiki-dark:#D2A8FF\"> makeCounter</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">();</span></span>\n<span class=\"line\"><span style=\"color:#8250DF;--shiki-dark:#D2A8FF\">a</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(); </span><span style=\"color:#8250DF;--shiki-dark:#D2A8FF\">a</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">();</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">console.</span><span style=\"color:#8250DF;--shiki-dark:#D2A8FF\">log</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#8250DF;--shiki-dark:#D2A8FF\">a</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(), </span><span style=\"color:#8250DF;--shiki-dark:#D2A8FF\">b</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">());</span></span></code></pre></div>\n","options":[{"text":"<code dir=\"ltr\">3 1</code>","why":"Correct. Each call of <code dir=\"ltr\">makeCounter</code> creates its own <code dir=\"ltr\">count</code>. <code dir=\"ltr\">a</code> has been called three times, <code dir=\"ltr\">b</code> once."},{"text":"<code dir=\"ltr\">3 4</code>","why":"That would need one shared <code dir=\"ltr\">count</code>. Every call of <code dir=\"ltr\">makeCounter</code> creates a separate one."},{"text":"<code dir=\"ltr\">1 1</code>","why":"<code dir=\"ltr\">count</code> is not reset on each call of the inner function; the closure keeps the same variable alive between calls."},{"text":"<code dir=\"ltr\">0 0</code>","why":"Each call of the returned function runs <code dir=\"ltr\">count++</code> before returning, so the first call already returns 1."}],"answer":0},{"q":"<p>Why is a closure-based id generator safer than a global <code dir=\"ltr\">let nextId = 1</code>?</p>","options":[{"text":"Closures run faster than global variables.","why":"Speed is not the point and the difference is negligible. The benefit is control over who can change the value."},{"text":"No code outside the generator can read or change the counter, so ids cannot be reset or duplicated by accident.","why":"Correct. The counter lives only in the closure, and the only way to touch it is to call the function you returned."},{"text":"Global variables are deleted after each function call.","why":"Globals live as long as the page does. That is exactly the problem, since any code can change them at any time."}],"answer":1}],"exercise":{"kind":"web","mode":"js","starter":{"js":"// A global counter: any code can break it. Move it into a closure.\nlet count = 0;\n\nfunction createIdGenerator(prefix) {\n  return () => {\n    count++;\n    return `${prefix}-${count}`;\n  };\n}\n\n// Return a function spend(cents) that subtracts from a private\n// remaining amount and returns what is left\nfunction createBudget(limitCents) {\n}\n\nconst nextId = createIdGenerator(\"exp\");\nconsole.log(nextId(), nextId());\n"},"solution":{"js":"function createIdGenerator(prefix) {\n  let count = 0;\n  return () => {\n    count++;\n    return `${prefix}-${count}`;\n  };\n}\n\nfunction createBudget(limitCents) {\n  let remaining = limitCents;\n  return (spentCents) => {\n    remaining -= spentCents;\n    return remaining;\n  };\n}\n\nconst nextId = createIdGenerator(\"exp\");\nconsole.log(nextId(), nextId());\n"},"checks":[{"id":"ids-sequence","test":"const gen = createIdGenerator('x');\nreturn gen() === 'x-1' && gen() === 'x-2' && gen() === 'x-3';\n"},{"id":"ids-independent","test":"const a = createIdGenerator('a');\nconst b = createIdGenerator('b');\na(); a();\nreturn a() === 'a-3' && b() === 'b-1';\n"},{"id":"no-global-count","test":"return typeof count === 'undefined';\n"},{"id":"budget","test":"const spend = createBudget(2000);\nif (typeof spend !== 'function') return false;\nreturn spend(450) === 1550 && spend(1220) === 330 && spend(500) === -170;\n"},{"id":"budget-independent","test":"const s1 = createBudget(1000);\nconst s2 = createBudget(5000);\ns1(400);\nreturn s2(100) === 4900 && s1(100) === 500;\n"}],"title":"Private counters with closures","prompt":"<p>The starter’s id generator shares one global <code dir=\"ltr\">count</code>, so two generators interfere and any code can reset it. Rewrite <code dir=\"ltr\">createIdGenerator(prefix)</code> so each generator has its <strong>own private counter</strong> and there is no global <code dir=\"ltr\">count</code> any more: a new generator’s first id is always <code dir=\"ltr\">prefix-1</code>.</p>\n<p>Then write <code dir=\"ltr\">createBudget(limitCents)</code>, which returns a function <code dir=\"ltr\">spend(cents)</code>. Each call subtracts <code dir=\"ltr\">cents</code> from a private remaining amount (starting at <code dir=\"ltr\">limitCents</code>) and returns what is left. It may go negative.</p>\n","hints":["Variables declared inside <code dir=\"ltr\">createIdGenerator</code> are created fresh on every call. Move <code dir=\"ltr\">let count = 0;</code> there and delete the global one.","<code dir=\"ltr\">createBudget</code> has the same shape: declare <code dir=\"ltr\">let remaining = limitCents;</code>, then <code dir=\"ltr\">return (cents) =&gt; { … };</code>.","Inside the returned function: <code dir=\"ltr\">remaining -= cents; return remaining;</code>."],"explanation":"<p>Declaring <code dir=\"ltr\">count</code> inside <code dir=\"ltr\">createIdGenerator</code> means every call creates a new variable, and the arrow function returned from that call closes over its own copy. That is why two generators no longer interfere and why the first id is always 1. With the global gone, nothing outside the closure can touch the counter. <code dir=\"ltr\">createBudget</code> uses the same pattern: <code dir=\"ltr\">remaining</code> survives between calls to <code dir=\"ltr\">spend</code> because the returned function still refers to it, yet no other code can read or change it except through <code dir=\"ltr\">spend</code>.</p>\n","checkLabels":{"ids-sequence":"A generator returns prefix-1, prefix-2, prefix-3…","ids-independent":"Two generators keep separate counts","no-global-count":"There is no global <code dir=\"ltr\">count</code> variable any more","budget":"<code dir=\"ltr\">spend</code> subtracts and returns what is left","budget-independent":"Two budgets keep separate remaining amounts"}},"words":739,"readMinutes":4}