[{"data":1,"prerenderedAt":3935},["ShallowReactive",2],{"page-\u002Fjs\u002F12-closures-and-lexical-scope":3},{"id":4,"title":5,"body":6,"description":30,"extension":3929,"meta":3930,"navigation":121,"path":3931,"seo":3932,"stem":3933,"__hash__":3934},"content\u002Fjs\u002F12-closures-and-lexical-scope.md","12 — Closures & Lexical Scope",{"type":7,"value":8,"toc":3904},"minimark",[9,13,251,390,533,662,962,1163,1350,1573,1761,1907,2062,2215,2424,2640,2833,3002,3242,3524,3743,3900],[10,11,5],"h1",{"id":12},"_12-closures-lexical-scope",[14,15,17,22,167,200],"question-wrapper",{"language":16},"javascript",[18,19,21],"h3",{"id":20},"q1-what-does-this-log","Q1. What does this log?",[23,24,25],"code-wrapper",{"language":16},[26,27,31],"pre",{"className":28,"code":29,"language":16,"meta":30,"style":30},"language-javascript shiki shiki-themes github-light github-dark","function makeCounter() {\n  let count = 0;\n  return function increment() {\n    count++;\n    return count;\n  };\n}\n\nconst counter = makeCounter();\nconsole.log(counter(), counter(), counter());\n","",[32,33,34,51,70,84,95,104,110,116,123,140],"code",{"__ignoreMap":30},[35,36,39,43,47],"span",{"class":37,"line":38},"line",1,[35,40,42],{"class":41},"svdQ7","function",[35,44,46],{"class":45},"sIsaT"," makeCounter",[35,48,50],{"class":49},"ssxIu","() {\n",[35,52,54,57,60,63,67],{"class":37,"line":53},2,[35,55,56],{"class":41},"  let",[35,58,59],{"class":49}," count ",[35,61,62],{"class":41},"=",[35,64,66],{"class":65},"snvgF"," 0",[35,68,69],{"class":49},";\n",[35,71,73,76,79,82],{"class":37,"line":72},3,[35,74,75],{"class":41},"  return",[35,77,78],{"class":41}," function",[35,80,81],{"class":45}," increment",[35,83,50],{"class":49},[35,85,87,90,93],{"class":37,"line":86},4,[35,88,89],{"class":49},"    count",[35,91,92],{"class":41},"++",[35,94,69],{"class":49},[35,96,98,101],{"class":37,"line":97},5,[35,99,100],{"class":41},"    return",[35,102,103],{"class":49}," count;\n",[35,105,107],{"class":37,"line":106},6,[35,108,109],{"class":49},"  };\n",[35,111,113],{"class":37,"line":112},7,[35,114,115],{"class":49},"}\n",[35,117,119],{"class":37,"line":118},8,[35,120,122],{"emptyLinePlaceholder":121},true,"\n",[35,124,126,129,132,135,137],{"class":37,"line":125},9,[35,127,128],{"class":41},"const",[35,130,131],{"class":65}," counter",[35,133,134],{"class":41}," =",[35,136,46],{"class":45},[35,138,139],{"class":49},"();\n",[35,141,143,146,149,152,155,158,160,162,164],{"class":37,"line":142},10,[35,144,145],{"class":49},"console.",[35,147,148],{"class":45},"log",[35,150,151],{"class":49},"(",[35,153,154],{"class":45},"counter",[35,156,157],{"class":49},"(), ",[35,159,154],{"class":45},[35,161,157],{"class":49},[35,163,154],{"class":45},[35,165,166],{"class":49},"());\n",[168,169,172,182,188,194],"ul",{"className":170},[171],"contains-task-list",[173,174,177,181],"li",{"className":175},[176],"task-list-item",[178,179],"input",{"disabled":121,"type":180},"checkbox"," 1 2 3",[173,183,185,187],{"className":184},[176],[178,186],{"disabled":121,"type":180}," 1 1 1",[173,189,191,193],{"className":190},[176],[178,192],{"disabled":121,"type":180}," undefined undefined undefined",[173,195,197,199],{"className":196},[176],[178,198],{"disabled":121,"type":180}," NaN NaN NaN",[201,202,203,207,215],"details",{},[204,205,206],"summary",{},"Show Answer",[208,209,210,214],"p",{},[211,212,213],"strong",{},"Answer:"," A — 1 2 3",[208,216,217,220,221,224,225,228,229,232,233,236,237,239,240,242,243,246,247,250],{},[211,218,219],{},"Explanation:"," ",[32,222,223],{},"increment"," forms a ",[211,226,227],{},"closure"," over ",[32,230,231],{},"count"," — it keeps a live reference to that variable binding even after ",[32,234,235],{},"makeCounter"," has returned. Each call mutates the same ",[32,238,231],{},", so it increments across calls rather than resetting. \"1 1 1\" is the trap a beginner falls into by assuming ",[32,241,231],{}," re-initializes to ",[32,244,245],{},"0"," on every call, as if it were a local variable reset each time — but it's only initialized once, when ",[32,248,249],{},"makeCounter()"," runs.",[14,252,253,257,335,365],{"language":16},[18,254,256],{"id":255},"q2-what-does-this-log","Q2. What does this log?",[23,258,259],{"language":16},[26,260,262],{"className":28,"code":261,"language":16,"meta":30,"style":30},"function outer() {\n  const secret = 42;\n  return () => secret;\n}\n\nconst getSecret = outer();\nconsole.log(getSecret());\n",[32,263,264,273,288,301,305,309,322],{"__ignoreMap":30},[35,265,266,268,271],{"class":37,"line":38},[35,267,42],{"class":41},[35,269,270],{"class":45}," outer",[35,272,50],{"class":49},[35,274,275,278,281,283,286],{"class":37,"line":53},[35,276,277],{"class":41},"  const",[35,279,280],{"class":65}," secret",[35,282,134],{"class":41},[35,284,285],{"class":65}," 42",[35,287,69],{"class":49},[35,289,290,292,295,298],{"class":37,"line":72},[35,291,75],{"class":41},[35,293,294],{"class":49}," () ",[35,296,297],{"class":41},"=>",[35,299,300],{"class":49}," secret;\n",[35,302,303],{"class":37,"line":86},[35,304,115],{"class":49},[35,306,307],{"class":37,"line":97},[35,308,122],{"emptyLinePlaceholder":121},[35,310,311,313,316,318,320],{"class":37,"line":106},[35,312,128],{"class":41},[35,314,315],{"class":65}," getSecret",[35,317,134],{"class":41},[35,319,270],{"class":45},[35,321,139],{"class":49},[35,323,324,326,328,330,333],{"class":37,"line":112},[35,325,145],{"class":49},[35,327,148],{"class":45},[35,329,151],{"class":49},[35,331,332],{"class":45},"getSecret",[35,334,166],{"class":49},[168,336,338,343,349,359],{"className":337},[171],[173,339,341,285],{"className":340},[176],[178,342],{"disabled":121,"type":180},[173,344,346,348],{"className":345},[176],[178,347],{"disabled":121,"type":180}," undefined",[173,350,352,354,355,358],{"className":351},[176],[178,353],{"disabled":121,"type":180}," Throws a ReferenceError because ",[32,356,357],{},"outer"," has already returned",[173,360,362,364],{"className":361},[176],[178,363],{"disabled":121,"type":180}," null",[201,366,367,369,374],{},[204,368,206],{},[208,370,371,373],{},[211,372,213],{}," A — 42",[208,375,376,378,379,382,383,386,387,389],{},[211,377,219],{}," Even though ",[32,380,381],{},"outer()"," has finished executing, the arrow function returned from it keeps ",[32,384,385],{},"secret"," alive via closure — the variable isn't garbage collected while a reachable function still references it. This is exactly what makes closures useful for private state: ",[32,388,385],{}," is inaccessible from outside except through the returned function.",[14,391,392,396,465,492],{"language":16},[18,393,395],{"id":394},"q3-what-does-this-log","Q3. What does this log?",[23,397,398],{"language":16},[26,399,401],{"className":28,"code":400,"language":16,"meta":30,"style":30},"for (var i = 0; i \u003C 3; i++) {\n  setTimeout(() => console.log(i), 0);\n}\n",[32,402,403,438,461],{"__ignoreMap":30},[35,404,405,408,411,414,417,419,421,424,427,430,433,435],{"class":37,"line":38},[35,406,407],{"class":41},"for",[35,409,410],{"class":49}," (",[35,412,413],{"class":41},"var",[35,415,416],{"class":49}," i ",[35,418,62],{"class":41},[35,420,66],{"class":65},[35,422,423],{"class":49},"; i ",[35,425,426],{"class":41},"\u003C",[35,428,429],{"class":65}," 3",[35,431,432],{"class":49},"; i",[35,434,92],{"class":41},[35,436,437],{"class":49},") {\n",[35,439,440,443,446,448,451,453,456,458],{"class":37,"line":53},[35,441,442],{"class":45},"  setTimeout",[35,444,445],{"class":49},"(() ",[35,447,297],{"class":41},[35,449,450],{"class":49}," console.",[35,452,148],{"class":45},[35,454,455],{"class":49},"(i), ",[35,457,245],{"class":65},[35,459,460],{"class":49},");\n",[35,462,463],{"class":37,"line":72},[35,464,115],{"class":49},[168,466,468,474,480,486],{"className":467},[171],[173,469,471,473],{"className":470},[176],[178,472],{"disabled":121,"type":180}," 3 3 3",[173,475,477,479],{"className":476},[176],[178,478],{"disabled":121,"type":180}," 0 1 2",[173,481,483,485],{"className":482},[176],[178,484],{"disabled":121,"type":180}," 0 1 2 3",[173,487,489,491],{"className":488},[176],[178,490],{"disabled":121,"type":180}," 2 2 2",[201,493,494,496,501],{},[204,495,206],{},[208,497,498,500],{},[211,499,213],{}," A — 3 3 3",[208,502,503,220,505,507,508,220,511,514,515,518,519,521,522,525,526,528,529,532],{},[211,504,219],{},[32,506,413],{}," is function\u002Fglobal-scoped, not block-scoped, so there is only ",[211,509,510],{},"one",[32,512,513],{},"i"," binding shared by the whole loop and every callback closure. By the time any ",[32,516,517],{},"setTimeout"," callback actually runs (after the synchronous loop has finished), ",[32,520,513],{}," has already reached ",[32,523,524],{},"3",", and all three callbacks read that same final value. \"0 1 2\" is what people expect from intuition — it's the correct answer only once ",[32,527,413],{}," is swapped for ",[32,530,531],{},"let"," (see next question).",[14,534,535,539,594,618],{"language":16},[18,536,538],{"id":537},"q4-what-does-this-log","Q4. What does this log?",[23,540,541],{"language":16},[26,542,544],{"className":28,"code":543,"language":16,"meta":30,"style":30},"for (let i = 0; i \u003C 3; i++) {\n  setTimeout(() => console.log(i), 0);\n}\n",[32,545,546,572,590],{"__ignoreMap":30},[35,547,548,550,552,554,556,558,560,562,564,566,568,570],{"class":37,"line":38},[35,549,407],{"class":41},[35,551,410],{"class":49},[35,553,531],{"class":41},[35,555,416],{"class":49},[35,557,62],{"class":41},[35,559,66],{"class":65},[35,561,423],{"class":49},[35,563,426],{"class":41},[35,565,429],{"class":65},[35,567,432],{"class":49},[35,569,92],{"class":41},[35,571,437],{"class":49},[35,573,574,576,578,580,582,584,586,588],{"class":37,"line":53},[35,575,442],{"class":45},[35,577,445],{"class":49},[35,579,297],{"class":41},[35,581,450],{"class":49},[35,583,148],{"class":45},[35,585,455],{"class":49},[35,587,245],{"class":65},[35,589,460],{"class":49},[35,591,592],{"class":37,"line":72},[35,593,115],{"class":49},[168,595,597,602,607,613],{"className":596},[171],[173,598,600,479],{"className":599},[176],[178,601],{"disabled":121,"type":180},[173,603,605,473],{"className":604},[176],[178,606],{"disabled":121,"type":180},[173,608,610,612],{"className":609},[176],[178,611],{"disabled":121,"type":180}," 0 0 0",[173,614,616,181],{"className":615},[176],[178,617],{"disabled":121,"type":180},[201,619,620,622,627],{},[204,621,206],{},[208,623,624,626],{},[211,625,213],{}," A — 0 1 2",[208,628,629,631,632,635,636,642,643,645,646,648,649,651,652,651,655,658,659,661],{},[211,630,219],{}," The ",[32,633,634],{},"for (let ...)"," form is special-cased by the spec: it creates a ",[211,637,638,639,641],{},"fresh binding of ",[32,640,513],{}," for each iteration",", copying the previous iteration's value into the new binding before running the loop body. Each ",[32,644,517],{}," callback closes over its own iteration's ",[32,647,513],{},", so they log ",[32,650,245],{},", ",[32,653,654],{},"1",[32,656,657],{},"2"," in order — this is the standard fix for the classic ",[32,660,413],{}," loop bug in Q3.",[14,663,664,668,894,919],{"language":16},[18,665,667],{"id":666},"q5-what-is-logged","Q5. What is logged?",[23,669,670],{"language":16},[26,671,673],{"className":28,"code":672,"language":16,"meta":30,"style":30},"function memoize(fn) {\n  const cache = new Map();\n  return function (n) {\n    if (cache.has(n)) return cache.get(n);\n    const result = fn(n);\n    cache.set(n, result);\n    return result;\n  };\n}\n\nlet calls = 0;\nconst square = memoize(n => { calls++; return n * n; });\n\nsquare(4);\nsquare(4);\nsquare(5);\nconsole.log(calls);\n",[32,674,675,690,707,720,746,761,772,779,783,787,791,805,843,848,861,872,884],{"__ignoreMap":30},[35,676,677,679,682,684,688],{"class":37,"line":38},[35,678,42],{"class":41},[35,680,681],{"class":45}," memoize",[35,683,151],{"class":49},[35,685,687],{"class":686},"sCrzJ","fn",[35,689,437],{"class":49},[35,691,692,694,697,699,702,705],{"class":37,"line":53},[35,693,277],{"class":41},[35,695,696],{"class":65}," cache",[35,698,134],{"class":41},[35,700,701],{"class":41}," new",[35,703,704],{"class":45}," Map",[35,706,139],{"class":49},[35,708,709,711,713,715,718],{"class":37,"line":72},[35,710,75],{"class":41},[35,712,78],{"class":41},[35,714,410],{"class":49},[35,716,717],{"class":686},"n",[35,719,437],{"class":49},[35,721,722,725,728,731,734,737,740,743],{"class":37,"line":86},[35,723,724],{"class":41},"    if",[35,726,727],{"class":49}," (cache.",[35,729,730],{"class":45},"has",[35,732,733],{"class":49},"(n)) ",[35,735,736],{"class":41},"return",[35,738,739],{"class":49}," cache.",[35,741,742],{"class":45},"get",[35,744,745],{"class":49},"(n);\n",[35,747,748,751,754,756,759],{"class":37,"line":97},[35,749,750],{"class":41},"    const",[35,752,753],{"class":65}," result",[35,755,134],{"class":41},[35,757,758],{"class":45}," fn",[35,760,745],{"class":49},[35,762,763,766,769],{"class":37,"line":106},[35,764,765],{"class":49},"    cache.",[35,767,768],{"class":45},"set",[35,770,771],{"class":49},"(n, result);\n",[35,773,774,776],{"class":37,"line":112},[35,775,100],{"class":41},[35,777,778],{"class":49}," result;\n",[35,780,781],{"class":37,"line":118},[35,782,109],{"class":49},[35,784,785],{"class":37,"line":125},[35,786,115],{"class":49},[35,788,789],{"class":37,"line":142},[35,790,122],{"emptyLinePlaceholder":121},[35,792,794,796,799,801,803],{"class":37,"line":793},11,[35,795,531],{"class":41},[35,797,798],{"class":49}," calls ",[35,800,62],{"class":41},[35,802,66],{"class":65},[35,804,69],{"class":49},[35,806,808,810,813,815,817,819,821,824,827,829,832,834,837,840],{"class":37,"line":807},12,[35,809,128],{"class":41},[35,811,812],{"class":65}," square",[35,814,134],{"class":41},[35,816,681],{"class":45},[35,818,151],{"class":49},[35,820,717],{"class":686},[35,822,823],{"class":41}," =>",[35,825,826],{"class":49}," { calls",[35,828,92],{"class":41},[35,830,831],{"class":49},"; ",[35,833,736],{"class":41},[35,835,836],{"class":49}," n ",[35,838,839],{"class":41},"*",[35,841,842],{"class":49}," n; });\n",[35,844,846],{"class":37,"line":845},13,[35,847,122],{"emptyLinePlaceholder":121},[35,849,851,854,856,859],{"class":37,"line":850},14,[35,852,853],{"class":45},"square",[35,855,151],{"class":49},[35,857,858],{"class":65},"4",[35,860,460],{"class":49},[35,862,864,866,868,870],{"class":37,"line":863},15,[35,865,853],{"class":45},[35,867,151],{"class":49},[35,869,858],{"class":65},[35,871,460],{"class":49},[35,873,875,877,879,882],{"class":37,"line":874},16,[35,876,853],{"class":45},[35,878,151],{"class":49},[35,880,881],{"class":65},"5",[35,883,460],{"class":49},[35,885,887,889,891],{"class":37,"line":886},17,[35,888,145],{"class":49},[35,890,148],{"class":45},[35,892,893],{"class":49},"(calls);\n",[168,895,897,903,908,914],{"className":896},[171],[173,898,900,902],{"className":899},[176],[178,901],{"disabled":121,"type":180}," 2",[173,904,906,429],{"className":905},[176],[178,907],{"disabled":121,"type":180},[173,909,911,913],{"className":910},[176],[178,912],{"disabled":121,"type":180}," 1",[173,915,917,66],{"className":916},[176],[178,918],{"disabled":121,"type":180},[201,920,921,923,928],{},[204,922,206],{},[208,924,925,927],{},[211,926,213],{}," A — 2",[208,929,930,932,933,936,937,940,941,944,945,947,948,951,952,955,956,958,959,961],{},[211,931,219],{}," The memoized wrapper closes over ",[32,934,935],{},"cache"," so it persists across calls. The first ",[32,938,939],{},"square(4)"," is a miss (computes, increments ",[32,942,943],{},"calls"," to 1, caches it), the second ",[32,946,939],{}," is a ",[211,949,950],{},"hit"," and returns the cached value without calling the original function, and ",[32,953,954],{},"square(5)"," is a new miss (increments ",[32,957,943],{}," to 2). Expecting ",[32,960,524],{}," assumes memoization isn't working — that's the whole point of the closure-backed cache.",[14,963,964,968,1087,1113],{"language":16},[18,965,967],{"id":966},"q6-what-does-this-log","Q6. What does this log?",[23,969,970],{"language":16},[26,971,973],{"className":28,"code":972,"language":16,"meta":30,"style":30},"function createBankAccount(balance) {\n  return {\n    deposit(amount) { balance += amount; return balance; },\n    getBalance() { return balance; }\n  };\n}\n\nconst acc = createBankAccount(100);\nacc.deposit(50);\nconsole.log(acc.balance);\n",[32,974,975,989,996,1020,1033,1037,1041,1045,1063,1078],{"__ignoreMap":30},[35,976,977,979,982,984,987],{"class":37,"line":38},[35,978,42],{"class":41},[35,980,981],{"class":45}," createBankAccount",[35,983,151],{"class":49},[35,985,986],{"class":686},"balance",[35,988,437],{"class":49},[35,990,991,993],{"class":37,"line":53},[35,992,75],{"class":41},[35,994,995],{"class":49}," {\n",[35,997,998,1001,1003,1006,1009,1012,1015,1017],{"class":37,"line":72},[35,999,1000],{"class":45},"    deposit",[35,1002,151],{"class":49},[35,1004,1005],{"class":686},"amount",[35,1007,1008],{"class":49},") { balance ",[35,1010,1011],{"class":41},"+=",[35,1013,1014],{"class":49}," amount; ",[35,1016,736],{"class":41},[35,1018,1019],{"class":49}," balance; },\n",[35,1021,1022,1025,1028,1030],{"class":37,"line":86},[35,1023,1024],{"class":45},"    getBalance",[35,1026,1027],{"class":49},"() { ",[35,1029,736],{"class":41},[35,1031,1032],{"class":49}," balance; }\n",[35,1034,1035],{"class":37,"line":97},[35,1036,109],{"class":49},[35,1038,1039],{"class":37,"line":106},[35,1040,115],{"class":49},[35,1042,1043],{"class":37,"line":112},[35,1044,122],{"emptyLinePlaceholder":121},[35,1046,1047,1049,1052,1054,1056,1058,1061],{"class":37,"line":118},[35,1048,128],{"class":41},[35,1050,1051],{"class":65}," acc",[35,1053,134],{"class":41},[35,1055,981],{"class":45},[35,1057,151],{"class":49},[35,1059,1060],{"class":65},"100",[35,1062,460],{"class":49},[35,1064,1065,1068,1071,1073,1076],{"class":37,"line":125},[35,1066,1067],{"class":49},"acc.",[35,1069,1070],{"class":45},"deposit",[35,1072,151],{"class":49},[35,1074,1075],{"class":65},"50",[35,1077,460],{"class":49},[35,1079,1080,1082,1084],{"class":37,"line":142},[35,1081,145],{"class":49},[35,1083,148],{"class":45},[35,1085,1086],{"class":49},"(acc.balance);\n",[168,1088,1090,1095,1101,1107],{"className":1089},[171],[173,1091,1093,348],{"className":1092},[176],[178,1094],{"disabled":121,"type":180},[173,1096,1098,1100],{"className":1097},[176],[178,1099],{"disabled":121,"type":180}," 150",[173,1102,1104,1106],{"className":1103},[176],[178,1105],{"disabled":121,"type":180}," 100",[173,1108,1110,1112],{"className":1109},[176],[178,1111],{"disabled":121,"type":180}," Throws a TypeError",[201,1114,1115,1117,1122],{},[204,1116,206],{},[208,1118,1119,1121],{},[211,1120,213],{}," A — undefined",[208,1123,1124,220,1126,1128,1129,1132,1133,1135,1136,1139,1140,1143,1144,1146,1147,1150,1151,1154,1155,1158,1159,1162],{},[211,1125,219],{},[32,1127,986],{}," is never assigned as a property of the returned object — it only exists as a variable in ",[32,1130,1131],{},"createBankAccount","'s scope, accessible to ",[32,1134,1070],{}," and ",[32,1137,1138],{},"getBalance"," through closure. ",[32,1141,1142],{},"acc.balance"," looks for an own property named ",[32,1145,986],{}," on ",[32,1148,1149],{},"acc",", which doesn't exist, so it's ",[32,1152,1153],{},"undefined",". This is precisely the ",[211,1156,1157],{},"private state pattern",": the real value (now ",[32,1160,1161],{},"150"," internally) is only reachable through the exposed methods, never by direct property access.",[14,1164,1165,1169,1279,1306],{"language":16},[18,1166,1168],{"id":1167},"q7-what-does-this-log","Q7. What does this log?",[23,1170,1171],{"language":16},[26,1172,1174],{"className":28,"code":1173,"language":16,"meta":30,"style":30},"function makeCounter() {\n  let c = 0;\n  return () => ++c;\n}\n\nconst a = makeCounter();\nconst b = makeCounter();\n\na();\na();\nconsole.log(a(), b());\n",[32,1175,1176,1184,1197,1211,1215,1219,1232,1245,1249,1256,1262],{"__ignoreMap":30},[35,1177,1178,1180,1182],{"class":37,"line":38},[35,1179,42],{"class":41},[35,1181,46],{"class":45},[35,1183,50],{"class":49},[35,1185,1186,1188,1191,1193,1195],{"class":37,"line":53},[35,1187,56],{"class":41},[35,1189,1190],{"class":49}," c ",[35,1192,62],{"class":41},[35,1194,66],{"class":65},[35,1196,69],{"class":49},[35,1198,1199,1201,1203,1205,1208],{"class":37,"line":72},[35,1200,75],{"class":41},[35,1202,294],{"class":49},[35,1204,297],{"class":41},[35,1206,1207],{"class":41}," ++",[35,1209,1210],{"class":49},"c;\n",[35,1212,1213],{"class":37,"line":86},[35,1214,115],{"class":49},[35,1216,1217],{"class":37,"line":97},[35,1218,122],{"emptyLinePlaceholder":121},[35,1220,1221,1223,1226,1228,1230],{"class":37,"line":106},[35,1222,128],{"class":41},[35,1224,1225],{"class":65}," a",[35,1227,134],{"class":41},[35,1229,46],{"class":45},[35,1231,139],{"class":49},[35,1233,1234,1236,1239,1241,1243],{"class":37,"line":112},[35,1235,128],{"class":41},[35,1237,1238],{"class":65}," b",[35,1240,134],{"class":41},[35,1242,46],{"class":45},[35,1244,139],{"class":49},[35,1246,1247],{"class":37,"line":118},[35,1248,122],{"emptyLinePlaceholder":121},[35,1250,1251,1254],{"class":37,"line":125},[35,1252,1253],{"class":45},"a",[35,1255,139],{"class":49},[35,1257,1258,1260],{"class":37,"line":142},[35,1259,1253],{"class":45},[35,1261,139],{"class":49},[35,1263,1264,1266,1268,1270,1272,1274,1277],{"class":37,"line":793},[35,1265,145],{"class":49},[35,1267,148],{"class":45},[35,1269,151],{"class":49},[35,1271,1253],{"class":45},[35,1273,157],{"class":49},[35,1275,1276],{"class":45},"b",[35,1278,166],{"class":49},[168,1280,1282,1288,1294,1300],{"className":1281},[171],[173,1283,1285,1287],{"className":1284},[176],[178,1286],{"disabled":121,"type":180}," 3 1",[173,1289,1291,1293],{"className":1290},[176],[178,1292],{"disabled":121,"type":180}," 2 1",[173,1295,1297,1299],{"className":1296},[176],[178,1298],{"disabled":121,"type":180}," 3 3",[173,1301,1303,1305],{"className":1302},[176],[178,1304],{"disabled":121,"type":180}," 1 1",[201,1307,1308,1310,1315],{},[204,1309,206],{},[208,1311,1312,1314],{},[211,1313,213],{}," A — 3 1",[208,1316,1317,1319,1320,1322,1323,220,1326,1329,1330,1135,1332,1334,1335,1337,1338,1341,1342,831,1344,1346,1347,1349],{},[211,1318,219],{}," Each call to ",[32,1321,249],{}," creates a ",[211,1324,1325],{},"brand-new, independent",[32,1327,1328],{},"c"," binding — ",[32,1331,1253],{},[32,1333,1276],{}," do not share state even though they came from the same factory function. ",[32,1336,1253],{}," has been invoked three times total by the time it's logged (two discarded calls, then a third inside the ",[32,1339,1340],{},"console.log","), reaching ",[32,1343,524],{},[32,1345,1276],{}," is invoked for the first time inside the same line, giving ",[32,1348,654],{},".",[14,1351,1352,1356,1495,1532],{"language":16},[18,1353,1355],{"id":1354},"q8-what-does-this-log","Q8. What does this log?",[23,1357,1358],{"language":16},[26,1359,1361],{"className":28,"code":1360,"language":16,"meta":30,"style":30},"function createLogger(config) {\n  return function log(msg) {\n    console.log(`[${config.level}] ${msg}`);\n  };\n}\n\nconst config = { level: 'info' };\nconst logger = createLogger(config);\nconfig.level = 'error';\n\nlogger('test');\n",[32,1362,1363,1377,1393,1423,1427,1431,1435,1453,1467,1479,1483],{"__ignoreMap":30},[35,1364,1365,1367,1370,1372,1375],{"class":37,"line":38},[35,1366,42],{"class":41},[35,1368,1369],{"class":45}," createLogger",[35,1371,151],{"class":49},[35,1373,1374],{"class":686},"config",[35,1376,437],{"class":49},[35,1378,1379,1381,1383,1386,1388,1391],{"class":37,"line":53},[35,1380,75],{"class":41},[35,1382,78],{"class":41},[35,1384,1385],{"class":45}," log",[35,1387,151],{"class":49},[35,1389,1390],{"class":686},"msg",[35,1392,437],{"class":49},[35,1394,1395,1398,1400,1402,1406,1408,1410,1413,1416,1418,1421],{"class":37,"line":72},[35,1396,1397],{"class":49},"    console.",[35,1399,148],{"class":45},[35,1401,151],{"class":49},[35,1403,1405],{"class":1404},"sJ6F3","`[${",[35,1407,1374],{"class":49},[35,1409,1349],{"class":1404},[35,1411,1412],{"class":49},"level",[35,1414,1415],{"class":1404},"}] ${",[35,1417,1390],{"class":49},[35,1419,1420],{"class":1404},"}`",[35,1422,460],{"class":49},[35,1424,1425],{"class":37,"line":86},[35,1426,109],{"class":49},[35,1428,1429],{"class":37,"line":97},[35,1430,115],{"class":49},[35,1432,1433],{"class":37,"line":106},[35,1434,122],{"emptyLinePlaceholder":121},[35,1436,1437,1439,1442,1444,1447,1450],{"class":37,"line":112},[35,1438,128],{"class":41},[35,1440,1441],{"class":65}," config",[35,1443,134],{"class":41},[35,1445,1446],{"class":49}," { level: ",[35,1448,1449],{"class":1404},"'info'",[35,1451,1452],{"class":49}," };\n",[35,1454,1455,1457,1460,1462,1464],{"class":37,"line":118},[35,1456,128],{"class":41},[35,1458,1459],{"class":65}," logger",[35,1461,134],{"class":41},[35,1463,1369],{"class":45},[35,1465,1466],{"class":49},"(config);\n",[35,1468,1469,1472,1474,1477],{"class":37,"line":125},[35,1470,1471],{"class":49},"config.level ",[35,1473,62],{"class":41},[35,1475,1476],{"class":1404}," 'error'",[35,1478,69],{"class":49},[35,1480,1481],{"class":37,"line":142},[35,1482,122],{"emptyLinePlaceholder":121},[35,1484,1485,1488,1490,1493],{"class":37,"line":793},[35,1486,1487],{"class":45},"logger",[35,1489,151],{"class":49},[35,1491,1492],{"class":1404},"'test'",[35,1494,460],{"class":49},[168,1496,1498,1508,1516,1525],{"className":1497},[171],[173,1499,1501,1503,1504,1507],{"className":1500},[176],[178,1502],{"disabled":121,"type":180}," \"",[35,1505,1506],{},"error"," test\"",[173,1509,1511,1503,1513,1507],{"className":1510},[176],[178,1512],{"disabled":121,"type":180},[35,1514,1515],{},"info",[173,1517,1519,1521,1522,1524],{"className":1518},[176],[178,1520],{"disabled":121,"type":180}," Throws a TypeError because ",[32,1523,1374],{}," was reassigned",[173,1526,1528,1503,1530,1507],{"className":1527},[176],[178,1529],{"disabled":121,"type":180},[35,1531,1153],{},[201,1533,1534,1536,1543],{},[204,1535,206],{},[208,1537,1538,1540,1541,1507],{},[211,1539,213],{}," A — \"",[35,1542,1506],{},[208,1544,1545,220,1547,1550,1551,1555,1556,1559,1560,1563,1564,1566,1567,1569,1570,1572],{},[211,1546,219],{},[211,1548,1549],{},"Debug:"," a closure captures the ",[1552,1553,1554],"em",{},"variable binding",", not a snapshot of its value at creation time — and for an object, that binding holds a reference. Mutating ",[32,1557,1558],{},"config.level"," after ",[32,1561,1562],{},"createLogger"," runs is visible to ",[32,1565,148],{}," the next time it reads ",[32,1568,1558],{},", because both ",[32,1571,1374],{}," (outer) and the closure's captured reference point to the same object. This surprises people who expect closures to \"freeze\" values the way default arguments do.",[14,1574,1575,1583,1675,1727],{"language":16},[18,1576,1578,1579,1582],{"id":1577},"q9-given-modern-js-engines-like-v8-what-typically-happens-to-bigarray-here","Q9. Given modern JS engines (like V8), what typically happens to ",[32,1580,1581],{},"bigArray"," here?",[23,1584,1585],{"language":16},[26,1586,1588],{"className":28,"code":1587,"language":16,"meta":30,"style":30},"function heavyClosure() {\n  const bigArray = new Array(1_000_000).fill('x');\n  return function tiny() {\n    return 'hi';\n  };\n}\n\nconst fn = heavyClosure();\n",[32,1589,1590,1599,1631,1642,1651,1655,1659,1663],{"__ignoreMap":30},[35,1591,1592,1594,1597],{"class":37,"line":38},[35,1593,42],{"class":41},[35,1595,1596],{"class":45}," heavyClosure",[35,1598,50],{"class":49},[35,1600,1601,1603,1606,1608,1610,1613,1615,1618,1621,1624,1626,1629],{"class":37,"line":53},[35,1602,277],{"class":41},[35,1604,1605],{"class":65}," bigArray",[35,1607,134],{"class":41},[35,1609,701],{"class":41},[35,1611,1612],{"class":45}," Array",[35,1614,151],{"class":49},[35,1616,1617],{"class":65},"1_000_000",[35,1619,1620],{"class":49},").",[35,1622,1623],{"class":45},"fill",[35,1625,151],{"class":49},[35,1627,1628],{"class":1404},"'x'",[35,1630,460],{"class":49},[35,1632,1633,1635,1637,1640],{"class":37,"line":72},[35,1634,75],{"class":41},[35,1636,78],{"class":41},[35,1638,1639],{"class":45}," tiny",[35,1641,50],{"class":49},[35,1643,1644,1646,1649],{"class":37,"line":86},[35,1645,100],{"class":41},[35,1647,1648],{"class":1404}," 'hi'",[35,1650,69],{"class":49},[35,1652,1653],{"class":37,"line":97},[35,1654,109],{"class":49},[35,1656,1657],{"class":37,"line":106},[35,1658,115],{"class":49},[35,1660,1661],{"class":37,"line":112},[35,1662,122],{"emptyLinePlaceholder":121},[35,1664,1665,1667,1669,1671,1673],{"class":37,"line":118},[35,1666,128],{"class":41},[35,1668,758],{"class":65},[35,1670,134],{"class":41},[35,1672,1596],{"class":45},[35,1674,139],{"class":49},[168,1676,1678,1690,1704,1715],{"className":1677},[171],[173,1679,1681,220,1683,1685,1686,1689],{"className":1680},[176],[178,1682],{"disabled":121,"type":180},[32,1684,1581],{}," is eligible for garbage collection because ",[32,1687,1688],{},"tiny"," never references it — modern engines only keep alive the specific bindings an escaping closure actually uses",[173,1691,1693,220,1695,1697,1698,1700,1701,1703],{"className":1692},[176],[178,1694],{"disabled":121,"type":180},[32,1696,1581],{}," is retained in memory forever as long as ",[32,1699,687],{}," exists, regardless of whether ",[32,1702,1688],{}," uses it",[173,1705,1707,220,1709,1711,1712,1714],{"className":1706},[176],[178,1708],{"disabled":121,"type":180},[32,1710,1581],{}," gets copied into ",[32,1713,1688],{},"'s closure, doubling memory usage",[173,1716,1718,220,1720,1723,1724,1726],{"className":1717},[176],[178,1719],{"disabled":121,"type":180},[32,1721,1722],{},"heavyClosure"," throws an error because ",[32,1725,1581],{}," is unused",[201,1728,1729,1731,1740],{},[204,1730,206],{},[208,1732,1733,1735,1736,1685,1738,1689],{},[211,1734,213],{}," A — ",[32,1737,1581],{},[32,1739,1688],{},[208,1741,1742,220,1744,1747,1748,1751,1752,1754,1755,1757,1758,1760],{},[211,1743,219],{},[211,1745,1746],{},"Performance:"," it's a common myth that a surviving closure keeps the ",[1552,1749,1750],{},"entire"," enclosing scope alive. Modern engines perform static analysis and only retain the variables an inner function actually touches; since ",[32,1753,1688],{}," never reads ",[32,1756,1581],{},", V8 can typically collect it once ",[32,1759,1722],{}," returns. That said, this is an engine optimization, not a spec guarantee — the safe, portable practice is still to avoid holding unnecessary large references in scope alongside a closure you intend to keep around, since older or simpler engines may retain the whole variable environment.",[14,1762,1763,1767,1843,1866],{"language":16},[18,1764,1766],{"id":1765},"q10-what-does-this-log","Q10. What does this log?",[23,1768,1769],{"language":16},[26,1770,1772],{"className":28,"code":1771,"language":16,"meta":30,"style":30},"for (var i = 0; i \u003C 3; i++) {\n  (function (j) {\n    setTimeout(() => console.log(j), 0);\n  })(i);\n}\n",[32,1773,1774,1800,1814,1834,1839],{"__ignoreMap":30},[35,1775,1776,1778,1780,1782,1784,1786,1788,1790,1792,1794,1796,1798],{"class":37,"line":38},[35,1777,407],{"class":41},[35,1779,410],{"class":49},[35,1781,413],{"class":41},[35,1783,416],{"class":49},[35,1785,62],{"class":41},[35,1787,66],{"class":65},[35,1789,423],{"class":49},[35,1791,426],{"class":41},[35,1793,429],{"class":65},[35,1795,432],{"class":49},[35,1797,92],{"class":41},[35,1799,437],{"class":49},[35,1801,1802,1805,1807,1809,1812],{"class":37,"line":53},[35,1803,1804],{"class":49},"  (",[35,1806,42],{"class":41},[35,1808,410],{"class":49},[35,1810,1811],{"class":686},"j",[35,1813,437],{"class":49},[35,1815,1816,1819,1821,1823,1825,1827,1830,1832],{"class":37,"line":72},[35,1817,1818],{"class":45},"    setTimeout",[35,1820,445],{"class":49},[35,1822,297],{"class":41},[35,1824,450],{"class":49},[35,1826,148],{"class":45},[35,1828,1829],{"class":49},"(j), ",[35,1831,245],{"class":65},[35,1833,460],{"class":49},[35,1835,1836],{"class":37,"line":86},[35,1837,1838],{"class":49},"  })(i);\n",[35,1840,1841],{"class":37,"line":97},[35,1842,115],{"class":49},[168,1844,1846,1851,1856,1861],{"className":1845},[171],[173,1847,1849,479],{"className":1848},[176],[178,1850],{"disabled":121,"type":180},[173,1852,1854,473],{"className":1853},[176],[178,1855],{"disabled":121,"type":180},[173,1857,1859,193],{"className":1858},[176],[178,1860],{"disabled":121,"type":180},[173,1862,1864,612],{"className":1863},[176],[178,1865],{"disabled":121,"type":180},[201,1867,1868,1870,1874],{},[204,1869,206],{},[208,1871,1872,626],{},[211,1873,213],{},[208,1875,1876,1878,1879,1881,1882,1884,1885,1888,1889,1891,1892,1894,1895,1897,1898,1900,1901,1903,1904,1906],{},[211,1877,219],{}," This is the classic pre-",[32,1880,531],{}," fix for the ",[32,1883,413],{}," loop bug: the ",[211,1886,1887],{},"IIFE"," (immediately invoked function expression) creates a new function scope on every iteration, and ",[32,1890,513],{},"'s current value is passed in as the argument ",[32,1893,1811],{},". Each ",[32,1896,517],{}," callback then closes over its own private ",[32,1899,1811],{},", not the shared loop ",[32,1902,513],{},", reproducing the same effect ",[32,1905,531],{}," gives you automatically.",[14,1908,1909,1913,2000,2035],{"language":16},[18,1910,1912],{"id":1911},"q11-what-does-this-log","Q11. What does this log?",[23,1914,1915],{"language":16},[26,1916,1918],{"className":28,"code":1917,"language":16,"meta":30,"style":30},"const fns = [];\nfor (let i = 0; i \u003C 3; i++) {\n  fns.push(() => i);\n}\nconsole.log(fns.map(fn => fn()));\n",[32,1919,1920,1932,1958,1973,1977],{"__ignoreMap":30},[35,1921,1922,1924,1927,1929],{"class":37,"line":38},[35,1923,128],{"class":41},[35,1925,1926],{"class":65}," fns",[35,1928,134],{"class":41},[35,1930,1931],{"class":49}," [];\n",[35,1933,1934,1936,1938,1940,1942,1944,1946,1948,1950,1952,1954,1956],{"class":37,"line":53},[35,1935,407],{"class":41},[35,1937,410],{"class":49},[35,1939,531],{"class":41},[35,1941,416],{"class":49},[35,1943,62],{"class":41},[35,1945,66],{"class":65},[35,1947,423],{"class":49},[35,1949,426],{"class":41},[35,1951,429],{"class":65},[35,1953,432],{"class":49},[35,1955,92],{"class":41},[35,1957,437],{"class":49},[35,1959,1960,1963,1966,1968,1970],{"class":37,"line":72},[35,1961,1962],{"class":49},"  fns.",[35,1964,1965],{"class":45},"push",[35,1967,445],{"class":49},[35,1969,297],{"class":41},[35,1971,1972],{"class":49}," i);\n",[35,1974,1975],{"class":37,"line":86},[35,1976,115],{"class":49},[35,1978,1979,1981,1983,1986,1989,1991,1993,1995,1997],{"class":37,"line":97},[35,1980,145],{"class":49},[35,1982,148],{"class":45},[35,1984,1985],{"class":49},"(fns.",[35,1987,1988],{"class":45},"map",[35,1990,151],{"class":49},[35,1992,687],{"class":686},[35,1994,823],{"class":41},[35,1996,758],{"class":45},[35,1998,1999],{"class":49},"()));\n",[168,2001,2003,2011,2019,2027],{"className":2002},[171],[173,2004,2006,220,2008],{"className":2005},[176],[178,2007],{"disabled":121,"type":180},[35,2009,2010],{},"0, 1, 2",[173,2012,2014,220,2016],{"className":2013},[176],[178,2015],{"disabled":121,"type":180},[35,2017,2018],{},"3, 3, 3",[173,2020,2022,220,2024],{"className":2021},[176],[178,2023],{"disabled":121,"type":180},[35,2025,2026],{},"2, 2, 2",[173,2028,2030,220,2032],{"className":2029},[176],[178,2031],{"disabled":121,"type":180},[35,2033,2034],{},"undefined, undefined, undefined",[201,2036,2037,2039,2045],{},[204,2038,206],{},[208,2040,2041,1735,2043],{},[211,2042,213],{},[35,2044,2010],{},[208,2046,2047,2049,2050,2052,2053,2055,2056,2058,2059,2061],{},[211,2048,219],{}," This confirms the per-iteration binding of ",[32,2051,531],{}," has nothing to do with timing or asynchrony — even called synchronously (no ",[32,2054,517],{}," involved), each pushed arrow function closes over its own iteration's ",[32,2057,513],{},". It's a common misconception that ",[32,2060,531],{},"'s loop fix is specifically an \"async trick\"; it's really about scoping, and this example proves that by removing the timer entirely.",[14,2063,2064,2072,2144,2174],{"language":16},[18,2065,2067,2068,2071],{"id":2066},"q12-what-happens-when-show-is-called","Q12. What happens when ",[32,2069,2070],{},"show()"," is called?",[23,2073,2074],{"language":16},[26,2075,2077],{"className":28,"code":2076,"language":16,"meta":30,"style":30},"let value = 'outer';\n\nfunction show() {\n  console.log(value);\n  let value = 'inner';\n}\n\nshow();\n",[32,2078,2079,2093,2097,2106,2116,2129,2133,2137],{"__ignoreMap":30},[35,2080,2081,2083,2086,2088,2091],{"class":37,"line":38},[35,2082,531],{"class":41},[35,2084,2085],{"class":49}," value ",[35,2087,62],{"class":41},[35,2089,2090],{"class":1404}," 'outer'",[35,2092,69],{"class":49},[35,2094,2095],{"class":37,"line":53},[35,2096,122],{"emptyLinePlaceholder":121},[35,2098,2099,2101,2104],{"class":37,"line":72},[35,2100,42],{"class":41},[35,2102,2103],{"class":45}," show",[35,2105,50],{"class":49},[35,2107,2108,2111,2113],{"class":37,"line":86},[35,2109,2110],{"class":49},"  console.",[35,2112,148],{"class":45},[35,2114,2115],{"class":49},"(value);\n",[35,2117,2118,2120,2122,2124,2127],{"class":37,"line":97},[35,2119,56],{"class":41},[35,2121,2085],{"class":49},[35,2123,62],{"class":41},[35,2125,2126],{"class":1404}," 'inner'",[35,2128,69],{"class":49},[35,2130,2131],{"class":37,"line":106},[35,2132,115],{"class":49},[35,2134,2135],{"class":37,"line":112},[35,2136,122],{"emptyLinePlaceholder":121},[35,2138,2139,2142],{"class":37,"line":118},[35,2140,2141],{"class":45},"show",[35,2143,139],{"class":49},[168,2145,2147,2156,2162,2168],{"className":2146},[171],[173,2148,2150,2152,2153],{"className":2149},[176],[178,2151],{"disabled":121,"type":180}," Throws ",[32,2154,2155],{},"ReferenceError: Cannot access 'value' before initialization",[173,2157,2159,2161],{"className":2158},[176],[178,2160],{"disabled":121,"type":180}," Logs \"outer\"",[173,2163,2165,2167],{"className":2164},[176],[178,2166],{"disabled":121,"type":180}," Logs \"inner\"",[173,2169,2171,2173],{"className":2170},[176],[178,2172],{"disabled":121,"type":180}," Logs undefined",[201,2175,2176,2178,2185],{},[204,2177,206],{},[208,2179,2180,2182,2183],{},[211,2181,213],{}," A — Throws ",[32,2184,2155],{},[208,2186,2187,220,2189,2191,2192,2195,2196,2198,2199,2202,2203,2206,2207,2210,2211,2214],{},[211,2188,219],{},[211,2190,1549],{}," the inner ",[32,2193,2194],{},"let value"," declaration is hoisted to the top of ",[32,2197,2141],{},"'s function scope (though not initialized), so it ",[211,2200,2201],{},"shadows"," the outer ",[32,2204,2205],{},"value"," for the entire function body — including the ",[32,2208,2209],{},"console.log(value)"," line that appears before the declaration. That reference falls into the ",[211,2212,2213],{},"temporal dead zone"," and throws, rather than falling back to the outer variable the way people expect closures\u002Fscoping to \"skip over\" an inner declaration that hasn't run yet.",[14,2216,2217,2221,2341,2367],{"language":16},[18,2218,2220],{"id":2219},"q13-what-does-this-log","Q13. What does this log?",[23,2222,2223],{"language":16},[26,2224,2226],{"className":28,"code":2225,"language":16,"meta":30,"style":30},"function createValidator(min) {\n  return function validate(value) {\n    return value >= min;\n  };\n}\n\nlet minValue = 10;\nconst validate = createValidator(minValue);\nminValue = 100;\n\nconsole.log(validate(50));\n",[32,2227,2228,2242,2257,2269,2273,2277,2281,2295,2308,2319,2323],{"__ignoreMap":30},[35,2229,2230,2232,2235,2237,2240],{"class":37,"line":38},[35,2231,42],{"class":41},[35,2233,2234],{"class":45}," createValidator",[35,2236,151],{"class":49},[35,2238,2239],{"class":686},"min",[35,2241,437],{"class":49},[35,2243,2244,2246,2248,2251,2253,2255],{"class":37,"line":53},[35,2245,75],{"class":41},[35,2247,78],{"class":41},[35,2249,2250],{"class":45}," validate",[35,2252,151],{"class":49},[35,2254,2205],{"class":686},[35,2256,437],{"class":49},[35,2258,2259,2261,2263,2266],{"class":37,"line":72},[35,2260,100],{"class":41},[35,2262,2085],{"class":49},[35,2264,2265],{"class":41},">=",[35,2267,2268],{"class":49}," min;\n",[35,2270,2271],{"class":37,"line":86},[35,2272,109],{"class":49},[35,2274,2275],{"class":37,"line":97},[35,2276,115],{"class":49},[35,2278,2279],{"class":37,"line":106},[35,2280,122],{"emptyLinePlaceholder":121},[35,2282,2283,2285,2288,2290,2293],{"class":37,"line":112},[35,2284,531],{"class":41},[35,2286,2287],{"class":49}," minValue ",[35,2289,62],{"class":41},[35,2291,2292],{"class":65}," 10",[35,2294,69],{"class":49},[35,2296,2297,2299,2301,2303,2305],{"class":37,"line":118},[35,2298,128],{"class":41},[35,2300,2250],{"class":65},[35,2302,134],{"class":41},[35,2304,2234],{"class":45},[35,2306,2307],{"class":49},"(minValue);\n",[35,2309,2310,2313,2315,2317],{"class":37,"line":125},[35,2311,2312],{"class":49},"minValue ",[35,2314,62],{"class":41},[35,2316,1106],{"class":65},[35,2318,69],{"class":49},[35,2320,2321],{"class":37,"line":142},[35,2322,122],{"emptyLinePlaceholder":121},[35,2324,2325,2327,2329,2331,2334,2336,2338],{"class":37,"line":793},[35,2326,145],{"class":49},[35,2328,148],{"class":45},[35,2330,151],{"class":49},[35,2332,2333],{"class":45},"validate",[35,2335,151],{"class":49},[35,2337,1075],{"class":65},[35,2339,2340],{"class":49},"));\n",[168,2342,2344,2350,2356,2362],{"className":2343},[171],[173,2345,2347,2349],{"className":2346},[176],[178,2348],{"disabled":121,"type":180}," true",[173,2351,2353,2355],{"className":2352},[176],[178,2354],{"disabled":121,"type":180}," false",[173,2357,2359,2361],{"className":2358},[176],[178,2360],{"disabled":121,"type":180}," Throws a ReferenceError",[173,2363,2365,348],{"className":2364},[176],[178,2366],{"disabled":121,"type":180},[201,2368,2369,2371,2376],{},[204,2370,206],{},[208,2372,2373,2375],{},[211,2374,213],{}," A — true",[208,2377,2378,220,2380,2382,2383,2385,2386,2389,2390,2393,2394,2397,2398,2401,2402,2404,2405,2408,2409,2411,2412,2415,2416,2419,2420,2423],{},[211,2379,219],{},[211,2381,1549],{}," unlike Q8's object example, ",[32,2384,2239],{}," here is a ",[211,2387,2388],{},"parameter",", and primitives are passed ",[211,2391,2392],{},"by value"," — ",[32,2395,2396],{},"createValidator(minValue)"," copies the number ",[32,2399,2400],{},"10"," into the parameter ",[32,2403,2239],{}," at call time. Reassigning the outer ",[32,2406,2407],{},"minValue"," variable afterward has no effect on that already-copied parameter, so ",[32,2410,2333],{},"'s closure still sees ",[32,2413,2414],{},"min = 10",", and ",[32,2417,2418],{},"50 >= 10"," is ",[32,2421,2422],{},"true",". This is the mirror image of Q8: closures capture bindings by reference, but a primitive value copied into a parameter is disconnected from the variable it came from.",[14,2425,2426,2430,2567,2599],{"language":16},[18,2427,2429],{"id":2428},"q14-what-does-this-log","Q14. What does this log?",[23,2431,2432],{"language":16},[26,2433,2435],{"className":28,"code":2434,"language":16,"meta":30,"style":30},"function createButtons(labels) {\n  return labels.map(label => () => console.log(`Clicked ${label}`));\n}\n\nconst labels = ['A', 'B'];\nconst handlers = createButtons(labels);\nlabels.push('C');\n\nhandlers.forEach(fn => fn());\n",[32,2436,2437,2451,2486,2490,2494,2517,2531,2545,2549],{"__ignoreMap":30},[35,2438,2439,2441,2444,2446,2449],{"class":37,"line":38},[35,2440,42],{"class":41},[35,2442,2443],{"class":45}," createButtons",[35,2445,151],{"class":49},[35,2447,2448],{"class":686},"labels",[35,2450,437],{"class":49},[35,2452,2453,2455,2458,2460,2462,2465,2467,2469,2471,2473,2475,2477,2480,2482,2484],{"class":37,"line":53},[35,2454,75],{"class":41},[35,2456,2457],{"class":49}," labels.",[35,2459,1988],{"class":45},[35,2461,151],{"class":49},[35,2463,2464],{"class":686},"label",[35,2466,823],{"class":41},[35,2468,294],{"class":49},[35,2470,297],{"class":41},[35,2472,450],{"class":49},[35,2474,148],{"class":45},[35,2476,151],{"class":49},[35,2478,2479],{"class":1404},"`Clicked ${",[35,2481,2464],{"class":49},[35,2483,1420],{"class":1404},[35,2485,2340],{"class":49},[35,2487,2488],{"class":37,"line":72},[35,2489,115],{"class":49},[35,2491,2492],{"class":37,"line":86},[35,2493,122],{"emptyLinePlaceholder":121},[35,2495,2496,2498,2501,2503,2506,2509,2511,2514],{"class":37,"line":97},[35,2497,128],{"class":41},[35,2499,2500],{"class":65}," labels",[35,2502,134],{"class":41},[35,2504,2505],{"class":49}," [",[35,2507,2508],{"class":1404},"'A'",[35,2510,651],{"class":49},[35,2512,2513],{"class":1404},"'B'",[35,2515,2516],{"class":49},"];\n",[35,2518,2519,2521,2524,2526,2528],{"class":37,"line":106},[35,2520,128],{"class":41},[35,2522,2523],{"class":65}," handlers",[35,2525,134],{"class":41},[35,2527,2443],{"class":45},[35,2529,2530],{"class":49},"(labels);\n",[35,2532,2533,2536,2538,2540,2543],{"class":37,"line":112},[35,2534,2535],{"class":49},"labels.",[35,2537,1965],{"class":45},[35,2539,151],{"class":49},[35,2541,2542],{"class":1404},"'C'",[35,2544,460],{"class":49},[35,2546,2547],{"class":37,"line":118},[35,2548,122],{"emptyLinePlaceholder":121},[35,2550,2551,2554,2557,2559,2561,2563,2565],{"class":37,"line":125},[35,2552,2553],{"class":49},"handlers.",[35,2555,2556],{"class":45},"forEach",[35,2558,151],{"class":49},[35,2560,687],{"class":686},[35,2562,823],{"class":41},[35,2564,758],{"class":45},[35,2566,166],{"class":49},[168,2568,2570,2576,2582,2588],{"className":2569},[171],[173,2571,2573,2575],{"className":2572},[176],[178,2574],{"disabled":121,"type":180}," \"Clicked A\" then \"Clicked B\" (2 lines total)",[173,2577,2579,2581],{"className":2578},[176],[178,2580],{"disabled":121,"type":180}," \"Clicked A\", \"Clicked B\", \"Clicked C\" (3 lines total)",[173,2583,2585,2587],{"className":2584},[176],[178,2586],{"disabled":121,"type":180}," \"Clicked C\" three times",[173,2589,2591,1521,2593,2595,2596],{"className":2590},[176],[178,2592],{"disabled":121,"type":180},[32,2594,2448],{}," was mutated after ",[32,2597,2598],{},".map",[201,2600,2601,2603,2608],{},[204,2602,206],{},[208,2604,2605,2607],{},[211,2606,213],{}," A — \"Clicked A\" then \"Clicked B\" (2 lines total)",[208,2609,2610,220,2612,2614,2615,2618,2619,2622,2623,2625,2626,220,2628,2630,2631,2633,2634,2636,2637,2639],{},[211,2611,219],{},[32,2613,2598],{}," runs synchronously and finishes building ",[32,2616,2617],{},"handlers"," (with exactly 2 functions) before ",[32,2620,2621],{},"labels.push('C')"," ever executes — pushing to ",[32,2624,2448],{}," afterward doesn't retroactively add a third handler. Additionally, each arrow function closes over its own ",[32,2627,2464],{},[211,2629,2388],{},", a primitive string copied per iteration by ",[32,2632,2598],{},", not a shared reference into the ",[32,2635,2448],{}," array — so even mutating ",[32,2638,2448],{}," further wouldn't change what the existing handlers log.",[14,2641,2642,2646,2759,2792],{"language":16},[18,2643,2645],{"id":2644},"q15-which-approach-actually-prevents-external-code-from-directly-overwriting-the-account-balance","Q15. Which approach actually prevents external code from directly overwriting the account balance?",[23,2647,2648],{"language":16},[26,2649,2651],{"className":28,"code":2650,"language":16,"meta":30,"style":30},"\u002F\u002F Option A\nclass BankAccount {\n  constructor(balance) { this.balance = balance; }\n}\n\n\u002F\u002F Option B\nfunction createAccount(balance) {\n  return {\n    deposit(amount) { balance += amount; return balance; },\n    getBalance() { return balance; }\n  };\n}\n",[32,2652,2653,2659,2669,2691,2695,2699,2704,2717,2723,2741,2751,2755],{"__ignoreMap":30},[35,2654,2655],{"class":37,"line":38},[35,2656,2658],{"class":2657},"sdCPZ","\u002F\u002F Option A\n",[35,2660,2661,2664,2667],{"class":37,"line":53},[35,2662,2663],{"class":41},"class",[35,2665,2666],{"class":45}," BankAccount",[35,2668,995],{"class":49},[35,2670,2671,2674,2676,2678,2681,2684,2687,2689],{"class":37,"line":72},[35,2672,2673],{"class":41},"  constructor",[35,2675,151],{"class":49},[35,2677,986],{"class":686},[35,2679,2680],{"class":49},") { ",[35,2682,2683],{"class":65},"this",[35,2685,2686],{"class":49},".balance ",[35,2688,62],{"class":41},[35,2690,1032],{"class":49},[35,2692,2693],{"class":37,"line":86},[35,2694,115],{"class":49},[35,2696,2697],{"class":37,"line":97},[35,2698,122],{"emptyLinePlaceholder":121},[35,2700,2701],{"class":37,"line":106},[35,2702,2703],{"class":2657},"\u002F\u002F Option B\n",[35,2705,2706,2708,2711,2713,2715],{"class":37,"line":112},[35,2707,42],{"class":41},[35,2709,2710],{"class":45}," createAccount",[35,2712,151],{"class":49},[35,2714,986],{"class":686},[35,2716,437],{"class":49},[35,2718,2719,2721],{"class":37,"line":118},[35,2720,75],{"class":41},[35,2722,995],{"class":49},[35,2724,2725,2727,2729,2731,2733,2735,2737,2739],{"class":37,"line":125},[35,2726,1000],{"class":45},[35,2728,151],{"class":49},[35,2730,1005],{"class":686},[35,2732,1008],{"class":49},[35,2734,1011],{"class":41},[35,2736,1014],{"class":49},[35,2738,736],{"class":41},[35,2740,1019],{"class":49},[35,2742,2743,2745,2747,2749],{"class":37,"line":142},[35,2744,1024],{"class":45},[35,2746,1027],{"class":49},[35,2748,736],{"class":41},[35,2750,1032],{"class":49},[35,2752,2753],{"class":37,"line":793},[35,2754,109],{"class":49},[35,2756,2757],{"class":37,"line":807},[35,2758,115],{"class":49},[168,2760,2762,2771,2777,2786],{"className":2761},[171],[173,2763,2765,2767,2768,2770],{"className":2764},[176],[178,2766],{"disabled":121,"type":180}," Option B — ",[32,2769,986],{}," lives only in closure scope, so there's no property to overwrite from outside",[173,2772,2774,2776],{"className":2773},[176],[178,2775],{"disabled":121,"type":180}," Option A — classes always enforce encapsulation",[173,2778,2780,2782,2783],{"className":2779},[176],[178,2781],{"disabled":121,"type":180}," Both are equally safe against ",[32,2784,2785],{},"account.balance = 999999",[173,2787,2789,2791],{"className":2788},[176],[178,2790],{"disabled":121,"type":180}," Neither prevents it; JavaScript has no way to hide state",[201,2793,2794,2796,2803],{},[204,2795,206],{},[208,2797,2798,2800,2801,2770],{},[211,2799,213],{}," A — Option B — ",[32,2802,986],{},[208,2804,2805,220,2807,2810,2811,2814,2815,2817,2818,2820,2821,2824,2825,2828,2829,2832],{},[211,2806,219],{},[211,2808,2809],{},"Idiom:"," in Option A, ",[32,2812,2813],{},"this.balance"," is a plain public property — anyone holding the instance can do ",[32,2816,2785],{}," directly, no method required. In Option B, ",[32,2819,986],{}," never becomes a property of the returned object; it only exists as a variable the closures can reach, so there is no ",[32,2822,2823],{},"account.balance"," to assign to at all. (A class using a true private field, ",[32,2826,2827],{},"#balance",", would achieve the same guarantee — the key distinction is private-by-closure or ",[32,2830,2831],{},"#field"," versus a plain public property, not \"class vs. factory function\" per se.)",[14,2834,2835,2839,2905,2956],{"language":16},[18,2836,2838],{"id":2837},"q16-this-click-handler-is-attached-to-a-large-widget-that-later-gets-removed-from-the-dom-whats-the-best-practice-to-prevent-a-memory-leak","Q16. This click handler is attached to a large widget that later gets removed from the DOM. What's the best practice to prevent a memory leak?",[23,2840,2841],{"language":16},[26,2842,2844],{"className":28,"code":2843,"language":16,"meta":30,"style":30},"function setupWidget(el, largeCachedData) {\n  el.addEventListener('click', function handler() {\n    console.log(largeCachedData.summary);\n  });\n}\n",[32,2845,2846,2865,2887,2896,2901],{"__ignoreMap":30},[35,2847,2848,2850,2853,2855,2858,2860,2863],{"class":37,"line":38},[35,2849,42],{"class":41},[35,2851,2852],{"class":45}," setupWidget",[35,2854,151],{"class":49},[35,2856,2857],{"class":686},"el",[35,2859,651],{"class":49},[35,2861,2862],{"class":686},"largeCachedData",[35,2864,437],{"class":49},[35,2866,2867,2870,2873,2875,2878,2880,2882,2885],{"class":37,"line":53},[35,2868,2869],{"class":49},"  el.",[35,2871,2872],{"class":45},"addEventListener",[35,2874,151],{"class":49},[35,2876,2877],{"class":1404},"'click'",[35,2879,651],{"class":49},[35,2881,42],{"class":41},[35,2883,2884],{"class":45}," handler",[35,2886,50],{"class":49},[35,2888,2889,2891,2893],{"class":37,"line":72},[35,2890,1397],{"class":49},[35,2892,148],{"class":45},[35,2894,2895],{"class":49},"(largeCachedData.summary);\n",[35,2897,2898],{"class":37,"line":86},[35,2899,2900],{"class":49},"  });\n",[35,2902,2903],{"class":37,"line":97},[35,2904,115],{"class":49},[168,2906,2908,2932,2941,2947],{"className":2907},[171],[173,2909,2911,2913,2914,2917,2918,2921,2922,2925,2926,2928,2929,2931],{"className":2910},[176],[178,2912],{"disabled":121,"type":180}," Call ",[32,2915,2916],{},"el.removeEventListener('click', handler)"," (or use an ",[32,2919,2920],{},"AbortController","\u002F",[32,2923,2924],{},"signal",") before discarding ",[32,2927,2857],{},", so the closure holding ",[32,2930,2862],{}," can be released",[173,2933,2935,2937,2938,2940],{"className":2934},[176],[178,2936],{"disabled":121,"type":180}," Nothing needs to change — removing ",[32,2939,2857],{}," from the DOM automatically releases its listeners and closures",[173,2942,2944,2946],{"className":2943},[176],[178,2945],{"disabled":121,"type":180}," Replace the named function with an arrow function to avoid the leak",[173,2948,2950,2952,2953,2955],{"className":2949},[176],[178,2951],{"disabled":121,"type":180}," Avoid closures entirely by making ",[32,2954,2862],{}," a global variable",[201,2957,2958,2960,2975],{},[204,2959,206],{},[208,2961,2962,2964,2965,2917,2967,2921,2969,2925,2971,2928,2973,2931],{},[211,2963,213],{}," A — Call ",[32,2966,2916],{},[32,2968,2920],{},[32,2970,2924],{},[32,2972,2857],{},[32,2974,2862],{},[208,2976,2977,220,2979,2981,2982,2985,2986,2988,2989,2991,2992,2994,2995,2997,2998,3001],{},[211,2978,219],{},[211,2980,1549],{}," as long as the listener reference exists, the ",[32,2983,2984],{},"handler"," closure keeps ",[32,2987,2862],{}," alive — and if something else (a framework, a detached-node cache, a reference cycle) keeps the element itself alive too, simply removing ",[32,2990,2857],{}," from the DOM tree doesn't guarantee garbage collection. Explicitly removing the listener (or attaching it with an ",[32,2993,2920],{},"'s ",[32,2996,2924],{}," and calling ",[32,2999,3000],{},"abort()",") breaks the reference chain so both the element and the closed-over data can be collected. Swapping to an arrow function changes nothing about what's captured.",[14,3003,3004,3008,3176,3212],{"language":16},[18,3005,3007],{"id":3006},"q17-whats-the-pitfall-in-this-memoization-helper","Q17. What's the pitfall in this memoization helper?",[23,3009,3010],{"language":16},[26,3011,3013],{"className":28,"code":3012,"language":16,"meta":30,"style":30},"function memoize(fn) {\n  const cache = {};\n  return function (obj) {\n    const key = JSON.stringify(obj);\n    if (key in cache) return cache[key];\n    return (cache[key] = fn(obj));\n  };\n}\n\nconst process = memoize(data => data.a + data.b);\nprocess({ a: 1, b: 2 });\nprocess({ b: 2, a: 1 });\n",[32,3014,3015,3027,3038,3051,3071,3089,3103,3107,3111,3115,3142,3160],{"__ignoreMap":30},[35,3016,3017,3019,3021,3023,3025],{"class":37,"line":38},[35,3018,42],{"class":41},[35,3020,681],{"class":45},[35,3022,151],{"class":49},[35,3024,687],{"class":686},[35,3026,437],{"class":49},[35,3028,3029,3031,3033,3035],{"class":37,"line":53},[35,3030,277],{"class":41},[35,3032,696],{"class":65},[35,3034,134],{"class":41},[35,3036,3037],{"class":49}," {};\n",[35,3039,3040,3042,3044,3046,3049],{"class":37,"line":72},[35,3041,75],{"class":41},[35,3043,78],{"class":41},[35,3045,410],{"class":49},[35,3047,3048],{"class":686},"obj",[35,3050,437],{"class":49},[35,3052,3053,3055,3058,3060,3063,3065,3068],{"class":37,"line":86},[35,3054,750],{"class":41},[35,3056,3057],{"class":65}," key",[35,3059,134],{"class":41},[35,3061,3062],{"class":65}," JSON",[35,3064,1349],{"class":49},[35,3066,3067],{"class":45},"stringify",[35,3069,3070],{"class":49},"(obj);\n",[35,3072,3073,3075,3078,3081,3084,3086],{"class":37,"line":97},[35,3074,724],{"class":41},[35,3076,3077],{"class":49}," (key ",[35,3079,3080],{"class":41},"in",[35,3082,3083],{"class":49}," cache) ",[35,3085,736],{"class":41},[35,3087,3088],{"class":49}," cache[key];\n",[35,3090,3091,3093,3096,3098,3100],{"class":37,"line":106},[35,3092,100],{"class":41},[35,3094,3095],{"class":49}," (cache[key] ",[35,3097,62],{"class":41},[35,3099,758],{"class":45},[35,3101,3102],{"class":49},"(obj));\n",[35,3104,3105],{"class":37,"line":112},[35,3106,109],{"class":49},[35,3108,3109],{"class":37,"line":118},[35,3110,115],{"class":49},[35,3112,3113],{"class":37,"line":125},[35,3114,122],{"emptyLinePlaceholder":121},[35,3116,3117,3119,3122,3124,3126,3128,3131,3133,3136,3139],{"class":37,"line":142},[35,3118,128],{"class":41},[35,3120,3121],{"class":65}," process",[35,3123,134],{"class":41},[35,3125,681],{"class":45},[35,3127,151],{"class":49},[35,3129,3130],{"class":686},"data",[35,3132,823],{"class":41},[35,3134,3135],{"class":49}," data.a ",[35,3137,3138],{"class":41},"+",[35,3140,3141],{"class":49}," data.b);\n",[35,3143,3144,3147,3150,3152,3155,3157],{"class":37,"line":793},[35,3145,3146],{"class":45},"process",[35,3148,3149],{"class":49},"({ a: ",[35,3151,654],{"class":65},[35,3153,3154],{"class":49},", b: ",[35,3156,657],{"class":65},[35,3158,3159],{"class":49}," });\n",[35,3161,3162,3164,3167,3169,3172,3174],{"class":37,"line":807},[35,3163,3146],{"class":45},[35,3165,3166],{"class":49},"({ b: ",[35,3168,657],{"class":65},[35,3170,3171],{"class":49},", a: ",[35,3173,654],{"class":65},[35,3175,3159],{"class":49},[168,3177,3179,3188,3194,3202],{"className":3178},[171],[173,3180,3182,220,3184,3187],{"className":3181},[176],[178,3183],{"disabled":121,"type":180},[32,3185,3186],{},"JSON.stringify"," is key-order-sensitive, so these logically-equal objects produce different cache keys (an unwanted cache miss), and the cache also grows unbounded with no eviction",[173,3189,3191,3193],{"className":3190},[176],[178,3192],{"disabled":121,"type":180}," This code throws a TypeError on the second call because the key already exists",[173,3195,3197,220,3199,3201],{"className":3196},[176],[178,3198],{"disabled":121,"type":180},[32,3200,3186],{}," automatically sorts object keys, so this memoization works correctly and efficiently",[173,3203,3205,3207,3208,3211],{"className":3204},[176],[178,3206],{"disabled":121,"type":180}," The cache is shared across all calls to ",[32,3209,3210],{},"memoize",", causing collisions between unrelated functions",[201,3213,3214,3216,3222],{},[204,3215,206],{},[208,3217,3218,1735,3220,3187],{},[211,3219,213],{},[32,3221,3186],{},[208,3223,3224,220,3226,220,3228,1135,3231,3234,3235,3237,3238,3241],{},[211,3225,219],{},[211,3227,2809],{},[32,3229,3230],{},"JSON.stringify({a:1,b:2})",[32,3232,3233],{},"JSON.stringify({b:2,a:1})"," produce different strings even though the objects are equivalent, so the second call recomputes instead of hitting the cache — a subtle correctness\u002Fperf bug, not a crash. Separately, nothing ever removes entries from ",[32,3236,935],{},", so a memoized function called with many distinct inputs grows the closure's cache indefinitely. Better practice: normalize keys (e.g. sort object keys before stringifying, or use a stable hash) and cap growth with an LRU eviction strategy or a ",[32,3239,3240],{},"WeakMap"," when keying by object identity is acceptable.",[14,3243,3244,3248,3463,3490],{"language":16},[18,3245,3247],{"id":3246},"q18-what-does-this-log","Q18. What does this log?",[23,3249,3250],{"language":16},[26,3251,3253],{"className":28,"code":3252,"language":16,"meta":30,"style":30},"const curry = fn => (...args) =>\n  args.length >= fn.length\n    ? fn(...args)\n    : (...more) => curry(fn)(...args, ...more);\n\nconst add3 = (a, b, c) => a + b + c;\nconst curried = curry(add3);\n\nconsole.log(curried(1)(2)(3), curried(1, 2)(3), curried(1, 2, 3));\n",[32,3254,3255,3282,3299,3313,3344,3348,3386,3400,3404],{"__ignoreMap":30},[35,3256,3257,3259,3262,3264,3266,3268,3270,3273,3276,3279],{"class":37,"line":38},[35,3258,128],{"class":41},[35,3260,3261],{"class":45}," curry",[35,3263,134],{"class":41},[35,3265,758],{"class":686},[35,3267,823],{"class":41},[35,3269,410],{"class":49},[35,3271,3272],{"class":41},"...",[35,3274,3275],{"class":686},"args",[35,3277,3278],{"class":49},") ",[35,3280,3281],{"class":41},"=>\n",[35,3283,3284,3287,3290,3293,3296],{"class":37,"line":53},[35,3285,3286],{"class":49},"  args.",[35,3288,3289],{"class":65},"length",[35,3291,3292],{"class":41}," >=",[35,3294,3295],{"class":49}," fn.",[35,3297,3298],{"class":65},"length\n",[35,3300,3301,3304,3306,3308,3310],{"class":37,"line":72},[35,3302,3303],{"class":41},"    ?",[35,3305,758],{"class":45},[35,3307,151],{"class":49},[35,3309,3272],{"class":41},[35,3311,3312],{"class":49},"args)\n",[35,3314,3315,3318,3320,3322,3325,3327,3329,3331,3334,3336,3339,3341],{"class":37,"line":86},[35,3316,3317],{"class":41},"    :",[35,3319,410],{"class":49},[35,3321,3272],{"class":41},[35,3323,3324],{"class":686},"more",[35,3326,3278],{"class":49},[35,3328,297],{"class":41},[35,3330,3261],{"class":45},[35,3332,3333],{"class":49},"(fn)(",[35,3335,3272],{"class":41},[35,3337,3338],{"class":49},"args, ",[35,3340,3272],{"class":41},[35,3342,3343],{"class":49},"more);\n",[35,3345,3346],{"class":37,"line":97},[35,3347,122],{"emptyLinePlaceholder":121},[35,3349,3350,3352,3355,3357,3359,3361,3363,3365,3367,3369,3371,3373,3376,3378,3381,3383],{"class":37,"line":106},[35,3351,128],{"class":41},[35,3353,3354],{"class":45}," add3",[35,3356,134],{"class":41},[35,3358,410],{"class":49},[35,3360,1253],{"class":686},[35,3362,651],{"class":49},[35,3364,1276],{"class":686},[35,3366,651],{"class":49},[35,3368,1328],{"class":686},[35,3370,3278],{"class":49},[35,3372,297],{"class":41},[35,3374,3375],{"class":49}," a ",[35,3377,3138],{"class":41},[35,3379,3380],{"class":49}," b ",[35,3382,3138],{"class":41},[35,3384,3385],{"class":49}," c;\n",[35,3387,3388,3390,3393,3395,3397],{"class":37,"line":112},[35,3389,128],{"class":41},[35,3391,3392],{"class":65}," curried",[35,3394,134],{"class":41},[35,3396,3261],{"class":45},[35,3398,3399],{"class":49},"(add3);\n",[35,3401,3402],{"class":37,"line":118},[35,3403,122],{"emptyLinePlaceholder":121},[35,3405,3406,3408,3410,3412,3415,3417,3419,3422,3424,3426,3428,3431,3433,3435,3437,3439,3441,3443,3445,3447,3449,3451,3453,3455,3457,3459,3461],{"class":37,"line":125},[35,3407,145],{"class":49},[35,3409,148],{"class":45},[35,3411,151],{"class":49},[35,3413,3414],{"class":45},"curried",[35,3416,151],{"class":49},[35,3418,654],{"class":65},[35,3420,3421],{"class":49},")(",[35,3423,657],{"class":65},[35,3425,3421],{"class":49},[35,3427,524],{"class":65},[35,3429,3430],{"class":49},"), ",[35,3432,3414],{"class":45},[35,3434,151],{"class":49},[35,3436,654],{"class":65},[35,3438,651],{"class":49},[35,3440,657],{"class":65},[35,3442,3421],{"class":49},[35,3444,524],{"class":65},[35,3446,3430],{"class":49},[35,3448,3414],{"class":45},[35,3450,151],{"class":49},[35,3452,654],{"class":65},[35,3454,651],{"class":49},[35,3456,657],{"class":65},[35,3458,651],{"class":49},[35,3460,524],{"class":65},[35,3462,2340],{"class":49},[168,3464,3466,3472,3478,3484],{"className":3465},[171],[173,3467,3469,3471],{"className":3468},[176],[178,3470],{"disabled":121,"type":180}," 6 6 6",[173,3473,3475,3477],{"className":3474},[176],[178,3476],{"disabled":121,"type":180}," Throws a TypeError because functions can't be called with zero, then more, arguments",[173,3479,3481,3483],{"className":3480},[176],[178,3482],{"disabled":121,"type":180}," NaN NaN 6",[173,3485,3487,3489],{"className":3486},[176],[178,3488],{"disabled":121,"type":180}," 6 NaN NaN",[201,3491,3492,3494,3499],{},[204,3493,206],{},[208,3495,3496,3498],{},[211,3497,213],{}," A — 6 6 6",[208,3500,3501,220,3503,3505,3506,3508,3509,3512,3513,3516,3517,3519,3520,3523],{},[211,3502,219],{},[211,3504,2809],{}," each partial call returns a new closure that remembers (",[32,3507,3275],{},") the arguments accumulated so far, comparing their count against ",[32,3510,3511],{},"fn.length"," (the declared arity of ",[32,3514,3515],{},"add3",", which is ",[32,3518,524],{},"). Once enough arguments have accumulated across however many calls it took, the closure invokes the original function. All three calling styles — one at a time, in pairs, or all at once — reach the same total of three arguments and the same result, ",[32,3521,3522],{},"6",". This accumulate-via-closure technique is the standard way to implement generic currying in JS.",[14,3525,3526,3530,3685,3716],{"language":16},[18,3527,3529],{"id":3528},"q19-for-a-list-of-10000-rows-that-re-renders-frequently-which-is-the-more-scalable-click-handling-strategy","Q19. For a list of 10,000 rows that re-renders frequently, which is the more scalable click-handling strategy?",[23,3531,3532],{"language":16},[26,3533,3535],{"className":28,"code":3534,"language":16,"meta":30,"style":30},"\u002F\u002F Approach A — one closure + one listener per row\nitems.forEach(item => {\n  const li = document.createElement('li');\n  li.addEventListener('click', () => selectItem(item.id));\n  list.appendChild(li);\n});\n\n\u002F\u002F Approach B — a single listener on the parent\nlist.addEventListener('click', e => {\n  const li = e.target.closest('li');\n  if (li) selectItem(li.dataset.id);\n});\n",[32,3536,3537,3542,3558,3580,3602,3613,3618,3622,3627,3647,3667,3681],{"__ignoreMap":30},[35,3538,3539],{"class":37,"line":38},[35,3540,3541],{"class":2657},"\u002F\u002F Approach A — one closure + one listener per row\n",[35,3543,3544,3547,3549,3551,3554,3556],{"class":37,"line":53},[35,3545,3546],{"class":49},"items.",[35,3548,2556],{"class":45},[35,3550,151],{"class":49},[35,3552,3553],{"class":686},"item",[35,3555,823],{"class":41},[35,3557,995],{"class":49},[35,3559,3560,3562,3565,3567,3570,3573,3575,3578],{"class":37,"line":72},[35,3561,277],{"class":41},[35,3563,3564],{"class":65}," li",[35,3566,134],{"class":41},[35,3568,3569],{"class":49}," document.",[35,3571,3572],{"class":45},"createElement",[35,3574,151],{"class":49},[35,3576,3577],{"class":1404},"'li'",[35,3579,460],{"class":49},[35,3581,3582,3585,3587,3589,3591,3594,3596,3599],{"class":37,"line":86},[35,3583,3584],{"class":49},"  li.",[35,3586,2872],{"class":45},[35,3588,151],{"class":49},[35,3590,2877],{"class":1404},[35,3592,3593],{"class":49},", () ",[35,3595,297],{"class":41},[35,3597,3598],{"class":45}," selectItem",[35,3600,3601],{"class":49},"(item.id));\n",[35,3603,3604,3607,3610],{"class":37,"line":97},[35,3605,3606],{"class":49},"  list.",[35,3608,3609],{"class":45},"appendChild",[35,3611,3612],{"class":49},"(li);\n",[35,3614,3615],{"class":37,"line":106},[35,3616,3617],{"class":49},"});\n",[35,3619,3620],{"class":37,"line":112},[35,3621,122],{"emptyLinePlaceholder":121},[35,3623,3624],{"class":37,"line":118},[35,3625,3626],{"class":2657},"\u002F\u002F Approach B — a single listener on the parent\n",[35,3628,3629,3632,3634,3636,3638,3640,3643,3645],{"class":37,"line":125},[35,3630,3631],{"class":49},"list.",[35,3633,2872],{"class":45},[35,3635,151],{"class":49},[35,3637,2877],{"class":1404},[35,3639,651],{"class":49},[35,3641,3642],{"class":686},"e",[35,3644,823],{"class":41},[35,3646,995],{"class":49},[35,3648,3649,3651,3653,3655,3658,3661,3663,3665],{"class":37,"line":142},[35,3650,277],{"class":41},[35,3652,3564],{"class":65},[35,3654,134],{"class":41},[35,3656,3657],{"class":49}," e.target.",[35,3659,3660],{"class":45},"closest",[35,3662,151],{"class":49},[35,3664,3577],{"class":1404},[35,3666,460],{"class":49},[35,3668,3669,3672,3675,3678],{"class":37,"line":793},[35,3670,3671],{"class":41},"  if",[35,3673,3674],{"class":49}," (li) ",[35,3676,3677],{"class":45},"selectItem",[35,3679,3680],{"class":49},"(li.dataset.id);\n",[35,3682,3683],{"class":37,"line":807},[35,3684,3617],{"class":49},[168,3686,3688,3694,3700,3706],{"className":3687},[171],[173,3689,3691,3693],{"className":3690},[176],[178,3692],{"disabled":121,"type":180}," Approach B — event delegation avoids allocating one closure and one listener per row, which matters a lot at scale",[173,3695,3697,3699],{"className":3696},[176],[178,3698],{"disabled":121,"type":180}," Approach A — more closures means more granular control and better performance",[173,3701,3703,3705],{"className":3702},[176],[178,3704],{"disabled":121,"type":180}," They perform identically; closures have no measurable cost",[173,3707,3709,3711,3712,3715],{"className":3708},[176],[178,3710],{"disabled":121,"type":180}," Approach A, but only if each closure is wrapped in ",[32,3713,3714],{},".bind()"," instead of an arrow function",[201,3717,3718,3720,3725],{},[204,3719,206],{},[208,3721,3722,3724],{},[211,3723,213],{}," A — Approach B — event delegation avoids allocating one closure and one listener per row, which matters a lot at scale",[208,3726,3727,220,3729,3731,3732,2921,3735,3738,3739,3742],{},[211,3728,219],{},[211,3730,1746],{}," Approach A allocates 10,000 separate closures and registers 10,000 separate listeners, all of which need to be torn down and recreated on every re-render — real memory and GC pressure at that scale. Approach B attaches a single listener once, using event bubbling and ",[32,3733,3734],{},"closest()",[32,3736,3737],{},"dataset"," to figure out which row was clicked, so re-rendering the list doesn't require touching listeners at all. This is the standard ",[211,3740,3741],{},"event delegation"," pattern for large or frequently-changing lists.",[14,3744,3745,3753,3841,3874],{"language":16},[18,3746,3748,3749,3752],{"id":3747},"q20-why-must-timeoutid-be-declared-in-the-outer-function-here-rather-than-inside-the-returned-function","Q20. Why must ",[32,3750,3751],{},"timeoutId"," be declared in the outer function here, rather than inside the returned function?",[23,3754,3755],{"language":16},[26,3756,3758],{"className":28,"code":3757,"language":16,"meta":30,"style":30},"function debounce(fn, delay) {\n  let timeoutId;\n  return function (...args) {\n    clearTimeout(timeoutId);\n    timeoutId = setTimeout(() => fn.apply(this, args), delay);\n  };\n}\n",[32,3759,3760,3778,3785,3799,3807,3833,3837],{"__ignoreMap":30},[35,3761,3762,3764,3767,3769,3771,3773,3776],{"class":37,"line":38},[35,3763,42],{"class":41},[35,3765,3766],{"class":45}," debounce",[35,3768,151],{"class":49},[35,3770,687],{"class":686},[35,3772,651],{"class":49},[35,3774,3775],{"class":686},"delay",[35,3777,437],{"class":49},[35,3779,3780,3782],{"class":37,"line":53},[35,3781,56],{"class":41},[35,3783,3784],{"class":49}," timeoutId;\n",[35,3786,3787,3789,3791,3793,3795,3797],{"class":37,"line":72},[35,3788,75],{"class":41},[35,3790,78],{"class":41},[35,3792,410],{"class":49},[35,3794,3272],{"class":41},[35,3796,3275],{"class":686},[35,3798,437],{"class":49},[35,3800,3801,3804],{"class":37,"line":86},[35,3802,3803],{"class":45},"    clearTimeout",[35,3805,3806],{"class":49},"(timeoutId);\n",[35,3808,3809,3812,3814,3817,3819,3821,3823,3826,3828,3830],{"class":37,"line":97},[35,3810,3811],{"class":49},"    timeoutId ",[35,3813,62],{"class":41},[35,3815,3816],{"class":45}," setTimeout",[35,3818,445],{"class":49},[35,3820,297],{"class":41},[35,3822,3295],{"class":49},[35,3824,3825],{"class":45},"apply",[35,3827,151],{"class":49},[35,3829,2683],{"class":65},[35,3831,3832],{"class":49},", args), delay);\n",[35,3834,3835],{"class":37,"line":106},[35,3836,109],{"class":49},[35,3838,3839],{"class":37,"line":112},[35,3840,115],{"class":49},[168,3842,3844,3850,3856,3865],{"className":3843},[171],[173,3845,3847,3849],{"className":3846},[176],[178,3848],{"disabled":121,"type":180}," So its value persists across multiple calls to the debounced function, letting each new call cancel the previous pending timer",[173,3851,3853,3855],{"className":3852},[176],[178,3854],{"disabled":121,"type":180}," It's purely stylistic — declaring it inside the returned function would behave identically",[173,3857,3859,3861,3862,3864],{"className":3858},[176],[178,3860],{"disabled":121,"type":180}," To avoid a naming collision with the ",[32,3863,3775],{}," parameter",[173,3866,3868,3870,3871,3873],{"className":3867},[176],[178,3869],{"disabled":121,"type":180}," Because ",[32,3872,531],{}," inside the returned function would throw a redeclaration error on the second call",[201,3875,3876,3878,3883],{},[204,3877,206],{},[208,3879,3880,3882],{},[211,3881,213],{}," A — So its value persists across multiple calls to the debounced function, letting each new call cancel the previous pending timer",[208,3884,3885,220,3887,3889,3890,3892,3893,3895,3896,3899],{},[211,3886,219],{},[211,3888,2809],{}," debouncing fundamentally needs state (the id of the currently-pending timer) that outlives any single invocation and is shared across every call to the returned function — exactly what a variable in the enclosing closure scope provides. If ",[32,3891,3751],{}," were declared inside the returned function instead, it would be reinitialized to ",[32,3894,1153],{}," on every call, ",[32,3897,3898],{},"clearTimeout(undefined)"," would be a no-op, and the previous timer would never actually get cancelled — defeating the entire point of debouncing.",[3901,3902,3903],"style",{},"html pre.shiki code .svdQ7, html code.shiki .svdQ7{--shiki-default:#D73A49;--shiki-github-dark:#F97583}html pre.shiki code .sIsaT, html code.shiki .sIsaT{--shiki-default:#6F42C1;--shiki-github-dark:#B392F0}html pre.shiki code .ssxIu, html code.shiki .ssxIu{--shiki-default:#24292E;--shiki-github-dark:#E1E4E8}html pre.shiki code .snvgF, html code.shiki .snvgF{--shiki-default:#005CC5;--shiki-github-dark:#79B8FF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .github-dark .shiki span {color: var(--shiki-github-dark);background: var(--shiki-github-dark-bg);font-style: var(--shiki-github-dark-font-style);font-weight: var(--shiki-github-dark-font-weight);text-decoration: var(--shiki-github-dark-text-decoration);}html.github-dark .shiki span {color: var(--shiki-github-dark);background: var(--shiki-github-dark-bg);font-style: var(--shiki-github-dark-font-style);font-weight: var(--shiki-github-dark-font-weight);text-decoration: var(--shiki-github-dark-text-decoration);}html pre.shiki code .sCrzJ, html code.shiki .sCrzJ{--shiki-default:#E36209;--shiki-github-dark:#FFAB70}html pre.shiki code .sJ6F3, html code.shiki .sJ6F3{--shiki-default:#032F62;--shiki-github-dark:#9ECBFF}html pre.shiki code .sdCPZ, html code.shiki .sdCPZ{--shiki-default:#6A737D;--shiki-github-dark:#6A737D}",{"title":30,"searchDepth":53,"depth":53,"links":3905},[3906,3907,3908,3909,3910,3911,3912,3913,3914,3916,3917,3918,3920,3921,3922,3923,3924,3925,3926,3927],{"id":20,"depth":72,"text":21},{"id":255,"depth":72,"text":256},{"id":394,"depth":72,"text":395},{"id":537,"depth":72,"text":538},{"id":666,"depth":72,"text":667},{"id":966,"depth":72,"text":967},{"id":1167,"depth":72,"text":1168},{"id":1354,"depth":72,"text":1355},{"id":1577,"depth":72,"text":3915},"Q9. Given modern JS engines (like V8), what typically happens to bigArray here?",{"id":1765,"depth":72,"text":1766},{"id":1911,"depth":72,"text":1912},{"id":2066,"depth":72,"text":3919},"Q12. What happens when show() is called?",{"id":2219,"depth":72,"text":2220},{"id":2428,"depth":72,"text":2429},{"id":2644,"depth":72,"text":2645},{"id":2837,"depth":72,"text":2838},{"id":3006,"depth":72,"text":3007},{"id":3246,"depth":72,"text":3247},{"id":3528,"depth":72,"text":3529},{"id":3747,"depth":72,"text":3928},"Q20. Why must timeoutId be declared in the outer function here, rather than inside the returned function?","md",{},"\u002Fjs\u002F12-closures-and-lexical-scope",{"title":5,"description":30},"js\u002F12-closures-and-lexical-scope","9uP5qEx9nJT-_4J4zpRcN92MjbqYmYaGjAVnbbo_W6A",1787335397334]