{"checkpoints":{"s-js-1":[{"q":"<p>What does this log?</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\"> total </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> \"0\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">;</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">total </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> total </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">+</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\">total </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> total </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">+</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> 1220</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\">(total);</span></span></code></pre></div>\n","options":[{"text":"<code dir=\"ltr\">1670</code>","why":"That needs numbers on both sides. <code dir=\"ltr\">total</code> starts as the string “0”, so every <code dir=\"ltr\">+</code> joins text instead of adding."},{"text":"<code dir=\"ltr\">&quot;1670&quot;</code>","why":"No addition ever happens here. <code dir=\"ltr\">+</code> with a string on one side joins the pieces as text."},{"text":"<code dir=\"ltr\">NaN</code>","why":"<code dir=\"ltr\">NaN</code> comes from maths that fails. Joining strings never fails, so no <code dir=\"ltr\">NaN</code> appears."},{"text":"<code dir=\"ltr\">04501220</code>","why":"Correct. “0” + 450 is “0450”, and “0450” + 1220 is “04501220”. Start the total at the number 0."}],"answer":3},{"q":"<p><code dir=\"ltr\">const count = 0;</code> followed later by <code dir=\"ltr\">count++;</code> throws <code dir=\"ltr\">TypeError: Assignment to constant variable.</code> What is the right fix?</p>","options":[{"text":"Declare it with <code dir=\"ltr\">var</code> so it works everywhere.","why":"<code dir=\"ltr\">var</code> would run, but it brings confusing scope rules. <code dir=\"ltr\">let</code> is the modern way to allow reassignment."},{"text":"Declare it with <code dir=\"ltr\">let count = 0;</code> because the value has to change.","why":"Correct. <code dir=\"ltr\">let</code> exists for names that are reassigned; <code dir=\"ltr\">const</code> is for names that never are."},{"text":"Replace <code dir=\"ltr\">count++</code> with <code dir=\"ltr\">count = count + 1</code>.","why":"That is still a reassignment, so a <code dir=\"ltr\">const</code> rejects it in exactly the same way."},{"text":"Wrap the increment in parentheses: <code dir=\"ltr\">(count)++</code>.","why":"Parentheses do not change what the statement does. It still tries to reassign a constant."}],"answer":1},{"q":"<p>A checkout shows “Total does not match” because <code dir=\"ltr\">subtotal === 0.3</code> is false after adding <code dir=\"ltr\">0.1</code> and <code dir=\"ltr\">0.2</code>. What is the best fix for a money app?</p>","options":[{"text":"Compare with <code dir=\"ltr\">==</code> instead of <code dir=\"ltr\">===</code>.","why":"<code dir=\"ltr\">==</code> only adds type conversion. Both sides are already numbers, and they really are slightly different."},{"text":"Compare <code dir=\"ltr\">subtotal.toFixed(2) === 0.3</code>.","why":"<code dir=\"ltr\">toFixed</code> returns a string, and a string is never strictly equal to a number, so this is always false."},{"text":"Store every amount as whole cents (integers), so <code dir=\"ltr\">10 + 20 === 30</code> exactly.","why":"Correct. Whole-number arithmetic is exact, so totals never drift. Convert to dollars only for display."},{"text":"Call <code dir=\"ltr\">parseFloat(subtotal)</code> before comparing.","why":"<code dir=\"ltr\">subtotal</code> is already a number. Parsing it changes nothing about the tiny binary rounding error."}],"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\">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\"> \"  Rent \"</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\"> clean</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\"> =</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> label.</span><span style=\"color:#8250DF;--shiki-dark:#D2A8FF\">trim</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">().</span><span style=\"color:#8250DF;--shiki-dark:#D2A8FF\">toLowerCase</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\">(label.</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">length</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, clean);</span></span></code></pre></div>\n","options":[{"text":"<code dir=\"ltr\">7 rent</code>","why":"Correct. String methods return new strings, so <code dir=\"ltr\">label</code> keeps its 7 characters, spaces included, and <code dir=\"ltr\">clean</code> is “rent”."},{"text":"<code dir=\"ltr\">4 rent</code>","why":"<code dir=\"ltr\">trim()</code> did not change <code dir=\"ltr\">label</code>; it returned a new string stored in <code dir=\"ltr\">clean</code>. <code dir=\"ltr\">label</code> still has its spaces."},{"text":"<code dir=\"ltr\">7 Rent</code>","why":"<code dir=\"ltr\">clean</code> comes from <code dir=\"ltr\">toLowerCase()</code>, so its first letter is lowercase."},{"text":"<code dir=\"ltr\">4 Rent</code>","why":"Neither part is right: <code dir=\"ltr\">label</code> is untouched (7 characters) and <code dir=\"ltr\">clean</code> is lowercased."}],"answer":0},{"q":"<p>With <code dir=\"ltr\">const cents = 1250;</code> and <code dir=\"ltr\">const item = &quot;lunch&quot;;</code>, which expression produces exactly <code dir=\"ltr\">Spent $12.50 on lunch</code>?</p>","options":[{"text":"<code dir=\"ltr\">&quot;Spent $&quot; + cents / 100 + &quot; on &quot; + item</code>","why":"Numbers drop trailing zeros when they become text, so this gives “Spent $12.5 on lunch”."},{"text":"<code dir=\"ltr\">`Spent ${cents / 100} on ${item}`</code>","why":"This is missing the dollar sign and, like the first option, shows 12.5 instead of 12.50."},{"text":"<code dir=\"ltr\">'Spent $${(cents / 100).toFixed(2)} on ${item}'</code>","why":"Single quotes make an ordinary string, so the <code dir=\"ltr\">${...}</code> parts are printed literally instead of being filled in."},{"text":"<code dir=\"ltr\">`Spent $${(cents / 100).toFixed(2)} on ${item}`</code>","why":"Correct. Backticks make a template literal, the first <code dir=\"ltr\">$</code> is a plain character, and <code dir=\"ltr\">toFixed(2)</code> keeps two decimals."}],"answer":3}],"s-js-2":[{"q":"<p>What does this log?</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"js\" data-index=\"2\"><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\"> sizeLabel</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 style=\"color:#CF222E;--shiki-dark:#FF7B72\">return</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\">  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\"> 1000</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">) </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">return</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> \"huge\"</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\"> \"small\"</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\">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\">sizeLabel</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">5000</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">));</span></span></code></pre></div>\n","options":[{"text":"<code dir=\"ltr\">huge</code>","why":"The first <code dir=\"ltr\">if</code> already matches 5000 and returns, so the “huge” check is never reached. Put the narrower check first."},{"text":"<code dir=\"ltr\">small</code>","why":"<code dir=\"ltr\">small</code> is returned only when neither condition is true, but 5000 is greater than 100."},{"text":"<code dir=\"ltr\">big</code>","why":"Correct, and it is a bug: <code dir=\"ltr\">return</code> ends the function at the first true condition, so the order of checks matters."},{"text":"<code dir=\"ltr\">undefined</code>","why":"Every path through the function returns a string, so the result is never <code dir=\"ltr\">undefined</code>."}],"answer":2},{"q":"<p>A function shows “No note” when <code dir=\"ltr\">if (note)</code> is false. Which of these notes is treated as missing?</p>","options":[{"text":"<code dir=\"ltr\">&quot;0&quot;</code>","why":"A non-empty string is truthy, even when it contains the character zero."},{"text":"<code dir=\"ltr\">&quot; &quot;</code> (a single space)","why":"A space is a character, so the string is not empty and counts as truthy."},{"text":"<code dir=\"ltr\">&quot;false&quot;</code>","why":"This is a five-letter string, not the boolean <code dir=\"ltr\">false</code>, so it is truthy."},{"text":"<code dir=\"ltr\">&quot;&quot;</code> (an empty string)","why":"Correct. The empty string is one of the eight falsy values."}],"answer":3},{"q":"<p>What does this log?</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"js\" data-index=\"3\"><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\"> 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\">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\"> 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\"> 5</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:#CF222E;--shiki-dark:#FF7B72\">  if</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\"> 3</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">) </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">break</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:#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\">(count);</span></span></code></pre></div>\n","options":[{"text":"<code dir=\"ltr\">3</code>","why":"Correct. Passes with <code dir=\"ltr\">i</code> = 0, 1 and 2 increase <code dir=\"ltr\">count</code>; when <code dir=\"ltr\">i</code> is 3, <code dir=\"ltr\">break</code> ends the loop before <code dir=\"ltr\">count++</code> runs."},{"text":"<code dir=\"ltr\">4</code>","why":"<code dir=\"ltr\">break</code> runs before <code dir=\"ltr\">count++</code> on the pass where <code dir=\"ltr\">i</code> is 3, so that pass does not count."},{"text":"<code dir=\"ltr\">5</code>","why":"That would be true without the <code dir=\"ltr\">break</code>. The loop stops early."},{"text":"<code dir=\"ltr\">2</code>","why":"The pass with <code dir=\"ltr\">i</code> = 0 counts too, so three passes complete before the <code dir=\"ltr\">break</code>."}],"answer":0},{"q":"<p>What does this log?</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"js\" data-index=\"4\"><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\">const</span><span style=\"color:#8250DF;--shiki-dark:#D2A8FF\"> add</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\"> =</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> (</span><span style=\"color:#953800;--shiki-dark:#FFA657\">a</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, </span><span style=\"color:#953800;--shiki-dark:#FFA657\">b</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\"> =</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> 10</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">) </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=></span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> a </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">+</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> b;</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\">add</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">5</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">), </span><span style=\"color:#8250DF;--shiki-dark:#D2A8FF\">add</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">5</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">0</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">), </span><span style=\"color:#8250DF;--shiki-dark:#D2A8FF\">add</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">5</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">null</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">));</span></span></code></pre></div>\n","options":[{"text":"<code dir=\"ltr\">15 15 15</code>","why":"A default applies only when the argument is missing or <code dir=\"ltr\">undefined</code>. 0 and <code dir=\"ltr\">null</code> are real arguments."},{"text":"<code dir=\"ltr\">15 5 5</code>","why":"Correct. Only the first call uses the default. In the last call <code dir=\"ltr\">null</code> is used, and in arithmetic it converts to 0."},{"text":"<code dir=\"ltr\">15 5 15</code>","why":"Passing <code dir=\"ltr\">null</code> does not trigger the default; only <code dir=\"ltr\">undefined</code> does."},{"text":"<code dir=\"ltr\">15 15 5</code>","why":"Passing 0 is a real argument, so <code dir=\"ltr\">b</code> is 0, not 10."}],"answer":1},{"q":"<p>What does this log?</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"js\" data-index=\"5\"><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\"> makeLimiter</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#953800;--shiki-dark:#FFA657\">max</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\"> used </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:#CF222E;--shiki-dark:#FF7B72\">    if</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> (used </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">>=</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> max) </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">return</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> false</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">;</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">    used</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:#0550AE;--shiki-dark:#79C0FF\"> true</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 style=\"color:#CF222E;--shiki-dark:#FF7B72\">const</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> canAdd</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\"> =</span><span style=\"color:#8250DF;--shiki-dark:#D2A8FF\"> makeLimiter</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">2</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\">canAdd</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(), </span><span style=\"color:#8250DF;--shiki-dark:#D2A8FF\">canAdd</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(), </span><span style=\"color:#8250DF;--shiki-dark:#D2A8FF\">canAdd</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">());</span></span></code></pre></div>\n","options":[{"text":"<code dir=\"ltr\">true true true</code>","why":"<code dir=\"ltr\">used</code> is remembered between calls by the closure, so the limit of 2 is reached."},{"text":"<code dir=\"ltr\">false false false</code>","why":"The first two calls find <code dir=\"ltr\">used</code> below <code dir=\"ltr\">max</code>, so they return <code dir=\"ltr\">true</code>."},{"text":"<code dir=\"ltr\">true true false</code>","why":"Correct. The closure keeps <code dir=\"ltr\">used</code> alive: it goes 0, 1, 2, and the third call finds the limit reached."},{"text":"<code dir=\"ltr\">true false false</code>","why":"The limit is 2, so two calls succeed before <code dir=\"ltr\">used &gt;= max</code> becomes true."}],"answer":2}],"s-js-3":[{"q":"<p><code dir=\"ltr\">const names = expenses.map((e) =&gt; { e.label.toUpperCase(); });</code> gives an array of <code dir=\"ltr\">undefined</code>. What is the fix?</p>","options":[{"text":"Use <code dir=\"ltr\">forEach</code> instead of <code dir=\"ltr\">map</code>.","why":"<code dir=\"ltr\">forEach</code> returns <code dir=\"ltr\">undefined</code> itself, so you would get no array at all."},{"text":"Remove the braces, <code dir=\"ltr\">(e) =&gt; e.label.toUpperCase()</code>, or add <code dir=\"ltr\">return</code> inside them.","why":"Correct. With braces the callback needs an explicit <code dir=\"ltr\">return</code>; otherwise it returns <code dir=\"ltr\">undefined</code> for every item."},{"text":"Use <code dir=\"ltr\">filter</code> instead of <code dir=\"ltr\">map</code>.","why":"<code dir=\"ltr\">filter</code> keeps or drops items; it does not transform them. With this callback it would return an empty array."},{"text":"Declare <code dir=\"ltr\">names</code> with <code dir=\"ltr\">let</code> instead of <code dir=\"ltr\">const</code>.","why":"How the result is stored does not change what <code dir=\"ltr\">map</code> returns."}],"answer":1},{"q":"<p>What does <code dir=\"ltr\">[5, 25, 100].sort()</code> return?</p>","options":[{"text":"<code dir=\"ltr\">[5, 25, 100]</code>","why":"That needs a comparator such as <code dir=\"ltr\">(a, b) =&gt; a - b</code>. The default sort compares text."},{"text":"<code dir=\"ltr\">[5, 100, 25]</code>","why":"As text, “1” sorts before “2” and “5”, so “100” comes first."},{"text":"<code dir=\"ltr\">[25, 5, 100]</code>","why":"Text comparison looks at the first character first: “1” &lt; “2” &lt; “5”."},{"text":"<code dir=\"ltr\">[100, 25, 5]</code>","why":"Correct. Without a comparator the numbers are compared as strings: “100” &lt; “25” &lt; “5”."}],"answer":3},{"q":"<p>What does this log?</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"js\" data-index=\"6\"><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\">const</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> settings</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\"> =</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> { currency: </span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"USD\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, limits: { food: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">400</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\"> copy</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\"> =</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> { </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">...</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">settings };</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">copy.limits.food </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> 500</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">;</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">copy.currency </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> \"EUR\"</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\">(settings.currency, settings.limits.food);</span></span></code></pre></div>\n","options":[{"text":"<code dir=\"ltr\">USD 400</code>","why":"Spread is shallow: <code dir=\"ltr\">copy.limits</code> and <code dir=\"ltr\">settings.limits</code> are the same inner object, so the food limit changes for both."},{"text":"<code dir=\"ltr\">EUR 500</code>","why":"<code dir=\"ltr\">currency</code> is a top-level property, copied by value into the new object, so changing <code dir=\"ltr\">copy.currency</code> leaves <code dir=\"ltr\">settings</code> alone."},{"text":"<code dir=\"ltr\">USD 500</code>","why":"Correct. Top-level properties were copied, but the nested <code dir=\"ltr\">limits</code> object is shared. Use <code dir=\"ltr\">structuredClone</code> for a deep copy."},{"text":"<code dir=\"ltr\">EUR 400</code>","why":"Both parts are reversed: the top-level change stays in the copy, and the nested change is shared."}],"answer":2},{"q":"<p>Which expression returns a saved discount of <code dir=\"ltr\">0</code> as 0, and uses 10 only when no discount was saved?</p>","options":[{"text":"<code dir=\"ltr\">user.discount ?? 10</code>","why":"Correct. <code dir=\"ltr\">??</code> falls back only for <code dir=\"ltr\">null</code> and <code dir=\"ltr\">undefined</code>, so a real 0 is kept."},{"text":"<code dir=\"ltr\">user.discount || 10</code>","why":"<code dir=\"ltr\">||</code> falls back for every falsy value, and 0 is falsy, so the saved discount is replaced by 10."},{"text":"<code dir=\"ltr\">user.discount ? user.discount : 10</code>","why":"The ternary tests truthiness, exactly like <code dir=\"ltr\">||</code>, so 0 becomes 10."},{"text":"<code dir=\"ltr\">user?.discount || 10</code>","why":"<code dir=\"ltr\">?.</code> only protects against <code dir=\"ltr\">user</code> being missing; the <code dir=\"ltr\">||</code> still throws away the 0."}],"answer":0},{"q":"<p>Pocket marks expenses as “reviewed” and checks <code dir=\"ltr\">isReviewed(id)</code> for every item on every render. Which structure fits best for the reviewed ids?</p>","options":[{"text":"A string of ids joined by commas.","why":"Strings must be searched character by character and can match parts of other ids, such as “exp-1” inside “exp-12”."},{"text":"A Map from id to the full expense object.","why":"You only need a yes/no answer, so storing whole expenses duplicates data that already lives in the list."},{"text":"An array that you push each id into.","why":"It works, but it allows duplicates and <code dir=\"ltr\">includes</code> searches the whole array on every check."},{"text":"A Set of ids.","why":"Correct. A Set stores each id once and <code dir=\"ltr\">has(id)</code> answers quickly without searching."}],"answer":3}],"s-js-4":[{"q":"<p>A script in the <code dir=\"ltr\">&lt;head&gt;</code> runs <code dir=\"ltr\">document.querySelector(&quot;#total&quot;).textContent = &quot;$0.00&quot;;</code> and throws <code dir=\"ltr\">Cannot set properties of null</code>. The id is spelled correctly. What fixes it?</p>","options":[{"text":"Use <code dir=\"ltr\">getElementById(&quot;total&quot;)</code> instead.","why":"Any lookup returns <code dir=\"ltr\">null</code> when the element does not exist yet. The problem is timing, not the method."},{"text":"Wrap the line in <code dir=\"ltr\">try</code>/<code dir=\"ltr\">catch</code>.","why":"That hides the error, and the total is still never set."},{"text":"Use <code dir=\"ltr\">innerHTML</code> instead of <code dir=\"ltr\">textContent</code>.","why":"The failure happens before either property is set: the element itself is <code dir=\"ltr\">null</code>."},{"text":"Add <code dir=\"ltr\">defer</code> to the script tag (or load it with <code dir=\"ltr\">type=&quot;module&quot;</code>), so it runs after the page is parsed.","why":"Correct. A plain script in the head runs before the body exists, so the element is not there yet."}],"answer":3},{"q":"<p>Pocket adds a click listener to each <code dir=\"ltr\">&lt;li&gt;</code> when the page loads. Expenses added later do not respond to clicks. What is the best fix?</p>","options":[{"text":"Put one listener on the list container and use <code dir=\"ltr\">event.target.closest(&quot;li&quot;)</code> to find the clicked item.","why":"Correct. Clicks on new items bubble to the same container, so delegation covers items added at any time."},{"text":"Add the listeners again a second later with <code dir=\"ltr\">setTimeout</code>.","why":"Items added after that second would still be missed. Timing is not the real problem."},{"text":"Put an <code dir=\"ltr\">onclick=&quot;...&quot;</code> attribute in each item’s HTML string.","why":"That mixes code into markup strings, risks injection, and still needs every item handled one by one."},{"text":"Re-add listeners to every item every second with <code dir=\"ltr\">setInterval</code>.","why":"It wastes work and stacks duplicate listeners on items that already had one."}],"answer":0},{"q":"<p>After pressing Enter in Pocket’s form, the page reloads and the URL gains <code dir=\"ltr\">?label=Tea</code>. The handler is <code dir=\"ltr\">form.addEventListener(&quot;submit&quot;, () =&gt; { addExpense(); });</code>. What is the cause?</p>","options":[{"text":"The <code dir=\"ltr\">submit</code> event only fires for mouse clicks, not for Enter.","why":"<code dir=\"ltr\">submit</code> fires however the form is submitted, which is exactly why you listen to it."},{"text":"<code dir=\"ltr\">addExpense</code> must be an <code dir=\"ltr\">async</code> function.","why":"Whether it is async does not affect the reload. The browser’s default action is still happening."},{"text":"The handler never calls <code dir=\"ltr\">event.preventDefault()</code>, so the browser performs its normal submission.","why":"Correct. The default action sends the form and loads a new page. Cancel it first thing in the handler."},{"text":"The form is missing an <code dir=\"ltr\">action</code> attribute.","why":"Without <code dir=\"ltr\">action</code> the form submits to the current page, which is the reload you see. The fix is to cancel the submission."}],"answer":2},{"q":"<p>After a reload, <code dir=\"ltr\">localStorage.getItem(&quot;pocket&quot;)</code> returns the text <code dir=\"ltr\">[object Object]</code>. What went wrong when saving?</p>","options":[{"text":"Storage was full, so the data was truncated.","why":"A full storage throws an error; it does not replace data with “[object Object]”."},{"text":"The object was passed to <code dir=\"ltr\">setItem</code> without <code dir=\"ltr\">JSON.stringify</code>, so it was converted with <code dir=\"ltr\">String()</code>.","why":"Correct. Storage keeps strings only. Serialise with <code dir=\"ltr\">JSON.stringify</code> and read back with <code dir=\"ltr\">JSON.parse</code>."},{"text":"<code dir=\"ltr\">JSON.parse</code> was called twice on load.","why":"Parsing happens on load and cannot change what was stored. The text was already wrong when saved."},{"text":"The key was misspelled when loading.","why":"A misspelled key returns <code dir=\"ltr\">null</code>, not “[object Object]”."}],"answer":1},{"q":"<p>The server answers this request with status 500 and an HTML error page. What happens?</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"js\" data-index=\"7\"><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\">async</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\"> function</span><span style=\"color:#8250DF;--shiki-dark:#D2A8FF\"> load</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\"> res</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\"> =</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\"> await</span><span style=\"color:#8250DF;--shiki-dark:#D2A8FF\"> fetch</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"/api/expenses\"</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\"> res.</span><span style=\"color:#8250DF;--shiki-dark:#D2A8FF\">json</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","options":[{"text":"<code dir=\"ltr\">fetch</code> rejects with an error saying “HTTP 500”.","why":"<code dir=\"ltr\">fetch</code> only rejects when the network fails. A 500 is still a complete HTTP response."},{"text":"<code dir=\"ltr\">load()</code> resolves with <code dir=\"ltr\">undefined</code>.","why":"<code dir=\"ltr\">res.json()</code> does not quietly return <code dir=\"ltr\">undefined</code>; it tries to parse the body and fails."},{"text":"<code dir=\"ltr\">fetch</code> resolves, then <code dir=\"ltr\">res.json()</code> rejects with a SyntaxError because the body is HTML, not JSON.","why":"Correct. Check <code dir=\"ltr\">res.ok</code> before parsing and throw a clear error of your own."},{"text":"The browser retries the request until it succeeds.","why":"Browsers do not retry failed HTTP responses automatically. Your code gets the 500 response."}],"answer":2}],"s-js-5":[{"q":"<p><code dir=\"ltr\">money.js</code> contains <code dir=\"ltr\">export function formatMoney(cents) { … }</code>. <code dir=\"ltr\">main.js</code> contains <code dir=\"ltr\">import formatMoney from &quot;./money.js&quot;;</code>. What happens?</p>","options":[{"text":"Loading fails: <code dir=\"ltr\">money.js</code> has no default export. Write <code dir=\"ltr\">import { formatMoney } from &quot;./money.js&quot;;</code>.","why":"Correct. Braces import named exports; without braces you are asking for a default export that does not exist."},{"text":"It works, because the names match.","why":"Names matter only for named imports, which need braces. Without braces, the import asks for the default export."},{"text":"<code dir=\"ltr\">formatMoney</code> is <code dir=\"ltr\">undefined</code> until it is first called.","why":"Imports are linked before any code runs. A missing export stops the module from loading at all."},{"text":"It works only if the file is renamed to <code dir=\"ltr\">money.mjs</code>.","why":"The file extension does not change how named and default exports work."}],"answer":0},{"q":"<p>What does this log?</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"js\" data-index=\"8\"><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\">class</span><span style=\"color:#953800;--shiki-dark:#FFA657\"> Store</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> {</span></span>\n<span class=\"line\"><span style=\"color:#953800;--shiki-dark:#FFA657\">  #items</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\">  add</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#953800;--shiki-dark:#FFA657\">x</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">) { </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">this</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">.#items.</span><span style=\"color:#8250DF;--shiki-dark:#D2A8FF\">push</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(x); }</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">  get</span><span style=\"color:#8250DF;--shiki-dark:#D2A8FF\"> size</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">() { </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">return</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> this</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">.#items.</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">length</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\">const</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> s</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\"> =</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\"> new</span><span style=\"color:#8250DF;--shiki-dark:#D2A8FF\"> Store</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">();</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">s.</span><span style=\"color:#8250DF;--shiki-dark:#D2A8FF\">add</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</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:#1F2328;--shiki-dark:#E6EDF3\">console.</span><span style=\"color:#8250DF;--shiki-dark:#D2A8FF\">log</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(s.size, s.items);</span></span></code></pre></div>\n","options":[{"text":"<code dir=\"ltr\">1 [1]</code>","why":"<code dir=\"ltr\">#items</code> and <code dir=\"ltr\">items</code> are different names. The private field is not exposed as a public <code dir=\"ltr\">items</code> property."},{"text":"<code dir=\"ltr\">undefined undefined</code>","why":"<code dir=\"ltr\">size</code> is a getter, so reading <code dir=\"ltr\">s.size</code> runs it and returns 1."},{"text":"It throws a SyntaxError.","why":"Only writing <code dir=\"ltr\">s.#items</code> outside the class is a syntax error. Reading a property that does not exist is allowed."},{"text":"<code dir=\"ltr\">1 undefined</code>","why":"Correct. The getter returns the length, and <code dir=\"ltr\">s.items</code> is simply a property that does not exist."}],"answer":3},{"q":"<p>Your loader catches every error in this block. A bug inside <code dir=\"ltr\">render</code> now goes unnoticed. What is the better structure?</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"js\" data-index=\"9\"><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\">try</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\"> data</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\"> =</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> JSON</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">.</span><span style=\"color:#8250DF;--shiki-dark:#D2A8FF\">parse</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(text);</span></span>\n<span class=\"line\"><span style=\"color:#8250DF;--shiki-dark:#D2A8FF\">  render</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(data);</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">} </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">catch</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> {</span></span>\n<span class=\"line\"><span style=\"color:#8250DF;--shiki-dark:#D2A8FF\">  render</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","options":[{"text":"Keep it, and leave the catch block empty instead.","why":"An empty catch hides even more: now nothing renders and nothing is reported."},{"text":"Wrap only <code dir=\"ltr\">JSON.parse</code> in <code dir=\"ltr\">try</code>/<code dir=\"ltr\">catch</code> with a fallback, and call <code dir=\"ltr\">render</code> outside it, so its bugs surface.","why":"Correct. Catch only what you expect and can handle, here bad JSON. Unexpected errors should reach the console."},{"text":"Wrap the whole app in one big <code dir=\"ltr\">try</code>/<code dir=\"ltr\">catch</code> at the top.","why":"That catches everything everywhere, which makes real bugs even harder to find."},{"text":"Remove the <code dir=\"ltr\">try</code> entirely.","why":"Then a corrupted saved value crashes the app on start-up, which is a real, expected failure you should handle."}],"answer":1},{"q":"<p>Pocket shows <code dir=\"ltr\">Total: $NaN</code> after you add an expense. A breakpoint in <code dir=\"ltr\">totalCents</code> shows the new expense has <code dir=\"ltr\">amount: undefined</code>. Where do you look next?</p>","options":[{"text":"The stylesheet, in case the total is hidden.","why":"The value itself is wrong, so styling cannot be the cause."},{"text":"The <code dir=\"ltr\">reduce</code> call inside <code dir=\"ltr\">totalCents</code>.","why":"<code dir=\"ltr\">reduce</code> is adding correctly; it received a bad value. The bug is earlier, where that value was made."},{"text":"The submit handler code that builds the new expense object.","why":"Correct. Trace the bad value back to where it was created, for example a misspelled field name such as <code dir=\"ltr\">data.get(&quot;amout&quot;)</code>."},{"text":"The storage size limit.","why":"A full storage throws on save. It does not change an amount to <code dir=\"ltr\">undefined</code> in memory."}],"answer":2},{"q":"<p>In Pocket, the delete handler calls <code dir=\"ltr\">button.closest(&quot;li&quot;).remove()</code>. Deleted expenses come back when the filter changes. Why?</p>","options":[{"text":"<code dir=\"ltr\">remove()</code> is asynchronous and had not finished.","why":"<code dir=\"ltr\">remove()</code> takes effect immediately. The element was removed; something drew it again."},{"text":"The browser caches the list between renders.","why":"There is no cache. <code dir=\"ltr\">render</code> builds the list fresh from the state each time."},{"text":"The filter select reloads the page.","why":"A <code dir=\"ltr\">change</code> event does not reload the page. It calls <code dir=\"ltr\">update</code>, which re-renders."},{"text":"The handler changed the page but not <code dir=\"ltr\">state.expenses</code>, so the next render draws the expense again.","why":"Correct. Change the state through <code dir=\"ltr\">update</code>, and let <code dir=\"ltr\">render</code> remove it from the page."}],"answer":3}]},"final":[{"q":"<p>What does <code dir=\"ltr\">console.log(typeof (450 + &quot;50&quot;), 450 - &quot;50&quot;)</code> print?</p>","options":[{"text":"<code dir=\"ltr\">number 400</code>","why":"With a string on one side, <code dir=\"ltr\">+</code> joins text, so the first result is a string."},{"text":"<code dir=\"ltr\">string 45050</code>","why":"<code dir=\"ltr\">-</code> only does maths, so “50” is converted to a number and the result is 400."},{"text":"<code dir=\"ltr\">string 400</code>","why":"Correct. <code dir=\"ltr\">+</code> joins to “45050”, a string; <code dir=\"ltr\">-</code> converts “50” to 50 and subtracts."},{"text":"<code dir=\"ltr\">number 500</code>","why":"Neither operation adds 450 and 50 as numbers here."}],"answer":2},{"q":"<p>What does <code dir=\"ltr\">[3, 1, 2].map((n) =&gt; n * 2).filter((n) =&gt; n &gt; 2)</code> return?</p>","options":[{"text":"<code dir=\"ltr\">[6, 4]</code>","why":"Correct. <code dir=\"ltr\">map</code> gives [6, 2, 4], then <code dir=\"ltr\">filter</code> keeps the values above 2, in their original order."},{"text":"<code dir=\"ltr\">[4, 6]</code>","why":"Neither <code dir=\"ltr\">map</code> nor <code dir=\"ltr\">filter</code> sorts. Items keep their order."},{"text":"<code dir=\"ltr\">[6, 2, 4]</code>","why":"That is the result of <code dir=\"ltr\">map</code> alone; <code dir=\"ltr\">filter</code> then removes the 2."},{"text":"<code dir=\"ltr\">[3, 2]</code>","why":"<code dir=\"ltr\">filter</code> runs on the doubled values, not on the original array."}],"answer":0},{"q":"<p>An expense has no <code dir=\"ltr\">receipt</code> property. Which expression throws?</p>","options":[{"text":"<code dir=\"ltr\">expense.receipt?.url</code>","why":"<code dir=\"ltr\">?.</code> stops at the missing receipt and returns <code dir=\"ltr\">undefined</code>."},{"text":"<code dir=\"ltr\">expense?.receipt</code>","why":"Reading a missing property is fine; it gives <code dir=\"ltr\">undefined</code>."},{"text":"<code dir=\"ltr\">expense.receipt ?? &quot;none&quot;</code>","why":"This reads a missing property, which is allowed, then falls back to “none”."},{"text":"<code dir=\"ltr\">expense.receipt.url</code>","why":"Correct. <code dir=\"ltr\">expense.receipt</code> is <code dir=\"ltr\">undefined</code>, and reading <code dir=\"ltr\">.url</code> from <code dir=\"ltr\">undefined</code> throws a TypeError."}],"answer":3},{"q":"<p>In what order are the letters logged?</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"js\" data-index=\"10\"><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:#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\">\"A\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">), </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 style=\"color:#CF222E;--shiki-dark:#FF7B72\">async</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\">  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\">\"B\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">);</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">  await</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> null</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:#0A3069;--shiki-dark:#A5D6FF\">\"C\"</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\">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\">\"D\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">);</span></span></code></pre></div>\n","options":[{"text":"A B C D","why":"The timer callback is a task, which waits until the script and all microtasks are done."},{"text":"B D C A","why":"Correct. B runs synchronously, <code dir=\"ltr\">await</code> pauses the function, D finishes the script, C resumes as a microtask, and A runs last as a task."},{"text":"B C D A","why":"<code dir=\"ltr\">await</code> pauses the async function even for a value that is not a promise, so D is logged before C."},{"text":"D B C A","why":"An async function runs synchronously until its first <code dir=\"ltr\">await</code>, so B is logged before D."}],"answer":1},{"q":"<p><code dir=\"ltr\">totalsByCategory</code> uses <code dir=\"ltr\">reduce</code> with <code dir=\"ltr\">{}</code> as the initial value and throws <code dir=\"ltr\">Cannot read properties of undefined</code> on the second expense. What is the most likely cause?</p>","options":[{"text":"The initial value should be <code dir=\"ltr\">[]</code>, not <code dir=\"ltr\">{}</code>.","why":"An object is right for per-category totals; an array would need different code."},{"text":"The expenses must be sorted by category first.","why":"Grouping with <code dir=\"ltr\">reduce</code> works in any order."},{"text":"<code dir=\"ltr\">reduce</code> cannot build objects, only numbers.","why":"The accumulator can be any value, including an object."},{"text":"The callback has braces but does not <code dir=\"ltr\">return totals</code>, so the second call receives <code dir=\"ltr\">undefined</code>.","why":"Correct. Whatever the callback returns becomes the next accumulator; without a <code dir=\"ltr\">return</code> that is <code dir=\"ltr\">undefined</code>."}],"answer":3},{"q":"<p>Two parts of Pocket each call <code dir=\"ltr\">createIdGenerator(&quot;exp&quot;)</code> and sometimes produce the same id. What is the right fix?</p>","options":[{"text":"Store the counter in a global <code dir=\"ltr\">var</code> instead.","why":"A global counter can be reset or changed by any code, which is the problem closures were solving."},{"text":"Call <code dir=\"ltr\">createIdGenerator(&quot;exp&quot;)</code> inside each click handler.","why":"Each call creates a fresh counter starting at 1, which makes duplicates even more likely."},{"text":"Create one generator in one module and import that same function wherever ids are needed.","why":"Correct. One generator means one counter, so every id it hands out is unique."},{"text":"Use <code dir=\"ltr\">Math.round(Math.random() * 10)</code> as the id.","why":"With only 11 possible values, collisions are guaranteed. Use one counter or <code dir=\"ltr\">crypto.randomUUID()</code>."}],"answer":2},{"q":"<p>A labels list is rendered with <code dir=\"ltr\">li.innerHTML = `&lt;b&gt;${label}&lt;/b&gt;`;</code> and a user saves the label <code dir=\"ltr\">&lt;img src=x onerror=alert(1)&gt;</code>. What is the safe fix?</p>","options":[{"text":"Wrap the label in quotes inside the template.","why":"Quotes are just characters to the HTML parser; the tag is still created and its code still runs."},{"text":"Create the <code dir=\"ltr\">&lt;b&gt;</code> with <code dir=\"ltr\">createElement</code> and set its <code dir=\"ltr\">textContent</code> to the label.","why":"Correct. <code dir=\"ltr\">textContent</code> never parses HTML, so the label is shown as plain text."},{"text":"Use <code dir=\"ltr\">outerHTML</code> instead of <code dir=\"ltr\">innerHTML</code>.","why":"<code dir=\"ltr\">outerHTML</code> also parses HTML, so it has the same injection problem."},{"text":"Limit labels to 20 characters.","why":"Short payloads can still run code. The fix is to never parse user text as HTML."}],"answer":1},{"q":"<p><code dir=\"ltr\">getJson</code> returns a promise that rejects. What does <code dir=\"ltr\">safeLoad()</code> do?</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"js\" data-index=\"11\"><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\">async</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\"> function</span><span style=\"color:#8250DF;--shiki-dark:#D2A8FF\"> safeLoad</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">() {</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">  try</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:#8250DF;--shiki-dark:#D2A8FF\"> getJson</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"/api/rates\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">);</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">  } </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">catch</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>\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></code></pre></div>\n","options":[{"text":"It returns a promise that rejects, because without <code dir=\"ltr\">await</code> the rejection happens after the <code dir=\"ltr\">try</code> block has finished.","why":"Correct. Write <code dir=\"ltr\">return await getJson(...)</code> so the rejection is thrown inside the <code dir=\"ltr\">try</code> and caught."},{"text":"It resolves with <code dir=\"ltr\">{}</code>.","why":"The <code dir=\"ltr\">catch</code> only sees errors thrown while the <code dir=\"ltr\">try</code> block runs, and nothing is thrown there without <code dir=\"ltr\">await</code>."},{"text":"It resolves with <code dir=\"ltr\">undefined</code>.","why":"The returned promise is adopted, so the result follows <code dir=\"ltr\">getJson</code>: it rejects."},{"text":"It throws synchronously when called.","why":"An async function never throws synchronously; it always returns a promise."}],"answer":0},{"q":"<p>You need <code dir=\"ltr\">amounts</code> sorted from largest to smallest for a chart, while another panel still shows <code dir=\"ltr\">amounts</code> in its original order. Which line is right?</p>","options":[{"text":"<code dir=\"ltr\">amounts.sort((a, b) =&gt; b - a)</code>","why":"The comparator is right, but <code dir=\"ltr\">sort</code> reorders the original array, breaking the other panel."},{"text":"<code dir=\"ltr\">amounts.toSorted()</code>","why":"It returns a copy, but without a comparator it sorts as text, ascending."},{"text":"<code dir=\"ltr\">[...amounts].sort()</code>","why":"The copy protects the original, but the default sort compares as text and sorts ascending."},{"text":"<code dir=\"ltr\">amounts.toSorted((a, b) =&gt; b - a)</code>","why":"Correct. A sorted copy, numeric and descending, leaving the original untouched."}],"answer":3},{"q":"<p><code dir=\"ltr\">items.forEach(store.add);</code> throws <code dir=\"ltr\">Cannot read properties of undefined (reading '#items')</code> inside <code dir=\"ltr\">add</code>. Which change fixes it?</p>","options":[{"text":"Declare <code dir=\"ltr\">store</code> with <code dir=\"ltr\">let</code> instead of <code dir=\"ltr\">const</code>.","why":"How the variable is declared does not change how <code dir=\"ltr\">add</code> is called."},{"text":"Write <code dir=\"ltr\">items.forEach(store.add());</code>.","why":"That calls <code dir=\"ltr\">add</code> once immediately with no item and passes its return value to <code dir=\"ltr\">forEach</code>."},{"text":"Write <code dir=\"ltr\">items.forEach((item) =&gt; store.add(item));</code>.","why":"Correct. The arrow function calls <code dir=\"ltr\">add</code> on <code dir=\"ltr\">store</code>, so <code dir=\"ltr\">this</code> is the store again."},{"text":"Assign <code dir=\"ltr\">const add = store.add;</code> first and pass <code dir=\"ltr\">add</code>.","why":"That is the same detached method under another name, so <code dir=\"ltr\">this</code> is still lost."}],"answer":2},{"q":"<p>The check <code dir=\"ltr\">if (amountInput.value == 0)</code> is meant to catch an amount of zero. Why does it also run when the field is empty?</p>","options":[{"text":"Empty number inputs contain the text “0”.","why":"An empty input’s value is the empty string “”, not “0”."},{"text":"<code dir=\"ltr\">==</code> converts <code dir=\"ltr\">&quot;&quot;</code> to the number 0 before comparing, so <code dir=\"ltr\">&quot;&quot; == 0</code> is true.","why":"Correct. Convert explicitly, check for empty input first, and compare with <code dir=\"ltr\">===</code>."},{"text":"<code dir=\"ltr\">value</code> is <code dir=\"ltr\">null</code> when the field is empty.","why":"<code dir=\"ltr\">value</code> is always a string; for an empty field it is “”."},{"text":"Number inputs return <code dir=\"ltr\">NaN</code> when empty, and <code dir=\"ltr\">NaN == 0</code> is true.","why":"<code dir=\"ltr\">value</code> is “” rather than <code dir=\"ltr\">NaN</code>, and <code dir=\"ltr\">NaN</code> is not equal to anything, not even itself."}],"answer":1},{"q":"<p>What happens with <code dir=\"ltr\">JSON.parse(JSON.stringify({ when: new Date() })).when.getFullYear()</code>?</p>","options":[{"text":"It throws a TypeError, because <code dir=\"ltr\">when</code> comes back as a string, which has no <code dir=\"ltr\">getFullYear</code> method.","why":"Correct. JSON stores dates as ISO strings. Convert back with <code dir=\"ltr\">new Date(text)</code>, or store dates as strings from the start."},{"text":"It returns the current year.","why":"That would need <code dir=\"ltr\">when</code> to be a Date again, but <code dir=\"ltr\">JSON.parse</code> has no way to know the string was a date."},{"text":"It returns <code dir=\"ltr\">NaN</code>.","why":"There is no Date object to return <code dir=\"ltr\">NaN</code> from; the method does not exist on a string at all."},{"text":"It returns <code dir=\"ltr\">undefined</code>.","why":"Calling something that is not a function throws; it does not return <code dir=\"ltr\">undefined</code>."}],"answer":0}],"glossary":[{"id":"type","term":"Type","definition":"The kind of a value, which decides what you can do with it. JavaScript’s basic types include number, string, boolean, undefined and null; the typeof operator reports a value’s type.","lesson":"l-js-1-2"},{"id":"variable","term":"Variable","definition":"A name that points at a value so a program can use it later. In JavaScript the value has a type, not the variable, so one variable can point at different types over time.","lesson":"l-js-1-2"},{"id":"let-const","term":"let and const","definition":"The two modern ways to declare a variable. A const name can never be pointed at another value; a let name can be reassigned. Default to const and use let only when needed.","lesson":"l-js-1-2"},{"id":"floating-point","term":"Floating-point number","definition":"A number stored in binary with limited precision, as all JavaScript numbers are. Many decimals cannot be stored exactly, so 0.1 + 0.2 gives 0.30000000000000004; store money as whole cents instead.","lesson":"l-js-1-3"},{"id":"strict-equality","term":"Strict equality (===)","definition":"A comparison that is true only when both values have the same type and the same value. Unlike loose equality (==), it never converts types first, so “5” === 5 is false.","lesson":"l-js-1-3"},{"id":"template-literal","term":"Template literal","definition":"A string written with backticks that can insert the value of any expression with ${ } and can span several lines, such as <code dir=\"ltr\">Total: ${total}</code>.","lesson":"l-js-1-4"},{"id":"truthy-falsy","term":"Truthy and falsy","definition":"How JavaScript treats any value used as a condition. Eight values are falsy: false, 0, -0, 0n, the empty string, null, undefined and NaN. Every other value is truthy.","lesson":"l-js-2-1"},{"id":"function","term":"Function","definition":"A named, reusable block of code. It declares parameters, receives arguments when called, runs its body and hands a result back with return; without return the result is undefined.","lesson":"l-js-2-3"},{"id":"arrow-function","term":"Arrow function","definition":"A shorter function syntax, such as (cents) =&gt; cents / 100. With a single expression after the arrow, that expression is returned automatically; with curly braces, an explicit return is needed.","lesson":"l-js-2-3"},{"id":"callback","term":"Callback","definition":"A function passed to another function, which decides when to call it. Array methods like map, event listeners and timers all take callbacks.","lesson":"l-js-2-3"},{"id":"scope","term":"Scope","definition":"The region of code where a name can be used. let and const are scoped to the nearest block, and name lookups go outward from inner scopes to outer ones, never inward.","lesson":"l-js-2-4"},{"id":"closure","term":"Closure","definition":"A function together with the variables from the scope where it was created. The function keeps access to them even after the outer function has returned, which gives it private, remembered state.","lesson":"l-js-2-4"},{"id":"array","term":"Array","definition":"An ordered list of values, written in square brackets and indexed from 0. Arrays have methods such as map, filter, find and reduce for transforming and searching their items.","lesson":"l-js-3-1"},{"id":"object","term":"Object","definition":"A value that groups named properties, such as { label: “Coffee”, amount: 450 }. Properties are read with dot notation, or with brackets when the name is in a variable.","lesson":"l-js-3-2"},{"id":"reference","term":"Reference","definition":"What a variable holds for an object or array: a pointer to it, not a copy. Assigning or passing it shares the same object, so a change through one name is visible through all.","lesson":"l-js-3-2"},{"id":"spread","term":"Spread syntax","definition":"Three dots that copy the items of an array or the properties of an object into a new one, as in […list, item] or { …expense, amount: 500 }. The copy is shallow.","lesson":"l-js-3-2"},{"id":"destructuring","term":"Destructuring","definition":"Syntax that unpacks properties or array items into variables in one step, such as const { label, amount } = expense. It supports default values and works in function parameters.","lesson":"l-js-3-2"},{"id":"reduce","term":"reduce","definition":"An array method that walks the items while carrying an accumulator, returning the final accumulator. Used for totals and grouping; always pass an initial value as its second argument.","lesson":"l-js-3-3"},{"id":"optional-chaining","term":"Optional chaining (?.)","definition":"An operator that reads a property only if the value on its left is not null or undefined, returning undefined instead of throwing a TypeError, as in expense.receipt?.url.","lesson":"l-js-3-4"},{"id":"nullish-coalescing","term":"Nullish coalescing (??)","definition":"An operator that returns its right side only when the left side is null or undefined. Unlike ||, it keeps real values such as 0 and the empty string.","lesson":"l-js-3-4"},{"id":"dom","term":"DOM","definition":"The Document Object Model: the browser’s live tree of objects representing the page. Changing these objects with JavaScript, for example an element’s textContent, updates what the user sees immediately.","lesson":"l-js-4-1"},{"id":"event-delegation","term":"Event delegation","definition":"Handling events for many child elements with one listener on their container. Events bubble up to the container, and event.target.closest() finds which child was involved, including children added later.","lesson":"l-js-4-2"},{"id":"json","term":"JSON","definition":"JavaScript Object Notation, a text format for data. JSON.stringify turns values into JSON text and JSON.parse turns it back; it holds strings, numbers, booleans, null, arrays and plain objects.","lesson":"l-js-4-4"},{"id":"promise","term":"Promise","definition":"An object standing for a result that is not ready yet. It starts pending and settles once, either fulfilled with a value or rejected with an error; then and catch attach what happens next.","lesson":"l-js-4-5"},{"id":"async-await","term":"async/await","definition":"Syntax for working with promises. Inside an async function, await pauses that function until a promise settles and gives its value, so asynchronous code reads top to bottom and errors are caught with try/catch.","lesson":"l-js-4-5"},{"id":"event-loop","term":"Event loop","definition":"The mechanism that lets single-threaded JavaScript wait without freezing. When the call stack is empty, it runs all queued promise callbacks (microtasks), then the next task such as a timer or click.","lesson":"l-js-4-5"},{"id":"module","term":"Module","definition":"A JavaScript file with its own scope that shares values with other files only through export and import. In the browser, the entry module is loaded with script type=“module”.","lesson":"l-js-5-1"},{"id":"class","term":"Class","definition":"A blueprint for objects that bundles data with the methods that act on it. new runs the constructor and returns an instance; private fields marked with # are hidden from outside code.","lesson":"l-js-5-2"},{"id":"stack-trace","term":"Stack trace","definition":"The list of function calls, with file names and line numbers, that led to an error, most recent first. It shows where the error happened and how the program got there.","lesson":"l-js-5-3"},{"id":"breakpoint","term":"Breakpoint","definition":"A marker in DevTools, or a debugger statement in code, that pauses execution on a line so you can inspect every variable, the call stack, and step through the code one line at a time.","lesson":"l-js-5-3"}]}