[{"data":1,"prerenderedAt":3496},["ShallowReactive",2],{"page-\u002Fjs\u002F26-performance-and-optimization":3},{"id":4,"title":5,"body":6,"description":3489,"extension":3490,"meta":3491,"navigation":58,"path":3492,"seo":3493,"stem":3494,"__hash__":3495},"content\u002Fjs\u002F26-performance-and-optimization.md","JavaScript 26 — Performance: Memory Leaks, Hidden Classes & Benchmarking",{"type":7,"value":8,"toc":3477},"minimark",[9,14,19,508,512,1056,1063,1710,1718,2201,2205,2848,2852,3091,3095,3187,3191,3195,3354,3473],[10,11,13],"h1",{"id":12},"_26-performance-memory-leaks-hidden-classes-benchmarking","26 — Performance: Memory Leaks, Hidden Classes & Benchmarking",[15,16,18],"h2",{"id":17},"v8-hidden-classes-and-inline-caches","V8 Hidden Classes and Inline Caches",[20,21,23],"code-wrapper",{"language":22},"javascript",[24,25,29],"pre",{"className":26,"code":27,"language":22,"meta":28,"style":28},"language-javascript shiki shiki-themes github-light github-dark","\u002F\u002F ── Hidden classes (Maps\u002FShapes): V8's object layout optimization ──\n\u002F\u002F V8 assigns objects a \"hidden class\" based on their property structure.\n\u002F\u002F Same property order → same hidden class → fast property access (inline caches).\n\n\u002F\u002F ✅ Fast: consistent property order (same hidden class for all instances)\nfunction Point(x, y) {\n    this.x = x;  \u002F\u002F hidden class transition: {} → {x}\n    this.y = y;  \u002F\u002F hidden class transition: {x} → {x, y}\n}\nconst p1 = new Point(1, 2);  \u002F\u002F hidden class: Point{x, y}\nconst p2 = new Point(3, 4);  \u002F\u002F same hidden class: Point{x, y} → fast!\n\n\u002F\u002F ❌ Slow: different property order (different hidden class transitions)\nfunction BadPoint1(x, y) { this.x = x; this.y = y; }\nfunction BadPoint2(x, y) { this.y = y; this.x = x; }  \u002F\u002F different transition order\nconst a = new BadPoint1(1, 2);  \u002F\u002F hidden class: {x, y}\nconst b = new BadPoint2(1, 2);  \u002F\u002F hidden class: {y, x} — DIFFERENT → can't share inline caches\n\n\u002F\u002F ❌ Adding properties after construction (causes hidden class transitions)\nconst p3 = new Point(1, 2);\np3.z = 3;  \u002F\u002F hidden class transition: Point{x, y} → Point{x, y, z} (slower for this instance)\n\u002F\u002F Future Point instances still use Point{x, y} — p3 has a different (slower) hidden class.\n\n\u002F\u002F ── Inline caches: V8 remembers the hidden class at property access sites ──\nfunction getX(obj) { return obj.x; }\ngetX(p1); getX(p1); getX(p1);  \u002F\u002F V8 caches: \"obj is Point{x,y}, x is at offset N\"\ngetX(p2);  \u002F\u002F same hidden class → cache hit → fast\ngetX(b);   \u002F\u002F different hidden class → cache miss → deoptimize → re-cache\n\n\u002F\u002F ── Best practices for hidden class stability ──\n\u002F\u002F 1. Declare all properties in the constructor (in the same order for all instances)\n\u002F\u002F 2. Don't add properties after construction (use a fixed set of properties)\n\u002F\u002F 3. Don't delete properties (causes transitions) — use null\u002Fundefined instead\n\u002F\u002F 4. Avoid polymorphic call sites (same function called with different hidden classes)\n","",[30,31,32,41,47,53,60,66,94,113,129,135,168,197,202,208,246,285,312,339,344,350,375,392,398,403,409,430,451,462,473,478,484,490,496,502],"code",{"__ignoreMap":28},[33,34,37],"span",{"class":35,"line":36},"line",1,[33,38,40],{"class":39},"sdCPZ","\u002F\u002F ── Hidden classes (Maps\u002FShapes): V8's object layout optimization ──\n",[33,42,44],{"class":35,"line":43},2,[33,45,46],{"class":39},"\u002F\u002F V8 assigns objects a \"hidden class\" based on their property structure.\n",[33,48,50],{"class":35,"line":49},3,[33,51,52],{"class":39},"\u002F\u002F Same property order → same hidden class → fast property access (inline caches).\n",[33,54,56],{"class":35,"line":55},4,[33,57,59],{"emptyLinePlaceholder":58},true,"\n",[33,61,63],{"class":35,"line":62},5,[33,64,65],{"class":39},"\u002F\u002F ✅ Fast: consistent property order (same hidden class for all instances)\n",[33,67,69,73,77,81,85,88,91],{"class":35,"line":68},6,[33,70,72],{"class":71},"svdQ7","function",[33,74,76],{"class":75},"sIsaT"," Point",[33,78,80],{"class":79},"ssxIu","(",[33,82,84],{"class":83},"sCrzJ","x",[33,86,87],{"class":79},", ",[33,89,90],{"class":83},"y",[33,92,93],{"class":79},") {\n",[33,95,97,101,104,107,110],{"class":35,"line":96},7,[33,98,100],{"class":99},"snvgF","    this",[33,102,103],{"class":79},".x ",[33,105,106],{"class":71},"=",[33,108,109],{"class":79}," x;  ",[33,111,112],{"class":39},"\u002F\u002F hidden class transition: {} → {x}\n",[33,114,116,118,121,123,126],{"class":35,"line":115},8,[33,117,100],{"class":99},[33,119,120],{"class":79},".y ",[33,122,106],{"class":71},[33,124,125],{"class":79}," y;  ",[33,127,128],{"class":39},"\u002F\u002F hidden class transition: {x} → {x, y}\n",[33,130,132],{"class":35,"line":131},9,[33,133,134],{"class":79},"}\n",[33,136,138,141,144,147,150,152,154,157,159,162,165],{"class":35,"line":137},10,[33,139,140],{"class":71},"const",[33,142,143],{"class":99}," p1",[33,145,146],{"class":71}," =",[33,148,149],{"class":71}," new",[33,151,76],{"class":75},[33,153,80],{"class":79},[33,155,156],{"class":99},"1",[33,158,87],{"class":79},[33,160,161],{"class":99},"2",[33,163,164],{"class":79},");  ",[33,166,167],{"class":39},"\u002F\u002F hidden class: Point{x, y}\n",[33,169,171,173,176,178,180,182,184,187,189,192,194],{"class":35,"line":170},11,[33,172,140],{"class":71},[33,174,175],{"class":99}," p2",[33,177,146],{"class":71},[33,179,149],{"class":71},[33,181,76],{"class":75},[33,183,80],{"class":79},[33,185,186],{"class":99},"3",[33,188,87],{"class":79},[33,190,191],{"class":99},"4",[33,193,164],{"class":79},[33,195,196],{"class":39},"\u002F\u002F same hidden class: Point{x, y} → fast!\n",[33,198,200],{"class":35,"line":199},12,[33,201,59],{"emptyLinePlaceholder":58},[33,203,205],{"class":35,"line":204},13,[33,206,207],{"class":39},"\u002F\u002F ❌ Slow: different property order (different hidden class transitions)\n",[33,209,211,213,216,218,220,222,224,227,230,232,234,237,239,241,243],{"class":35,"line":210},14,[33,212,72],{"class":71},[33,214,215],{"class":75}," BadPoint1",[33,217,80],{"class":79},[33,219,84],{"class":83},[33,221,87],{"class":79},[33,223,90],{"class":83},[33,225,226],{"class":79},") { ",[33,228,229],{"class":99},"this",[33,231,103],{"class":79},[33,233,106],{"class":71},[33,235,236],{"class":79}," x; ",[33,238,229],{"class":99},[33,240,120],{"class":79},[33,242,106],{"class":71},[33,244,245],{"class":79}," y; }\n",[33,247,249,251,254,256,258,260,262,264,266,268,270,273,275,277,279,282],{"class":35,"line":248},15,[33,250,72],{"class":71},[33,252,253],{"class":75}," BadPoint2",[33,255,80],{"class":79},[33,257,84],{"class":83},[33,259,87],{"class":79},[33,261,90],{"class":83},[33,263,226],{"class":79},[33,265,229],{"class":99},[33,267,120],{"class":79},[33,269,106],{"class":71},[33,271,272],{"class":79}," y; ",[33,274,229],{"class":99},[33,276,103],{"class":79},[33,278,106],{"class":71},[33,280,281],{"class":79}," x; }  ",[33,283,284],{"class":39},"\u002F\u002F different transition order\n",[33,286,288,290,293,295,297,299,301,303,305,307,309],{"class":35,"line":287},16,[33,289,140],{"class":71},[33,291,292],{"class":99}," a",[33,294,146],{"class":71},[33,296,149],{"class":71},[33,298,215],{"class":75},[33,300,80],{"class":79},[33,302,156],{"class":99},[33,304,87],{"class":79},[33,306,161],{"class":99},[33,308,164],{"class":79},[33,310,311],{"class":39},"\u002F\u002F hidden class: {x, y}\n",[33,313,315,317,320,322,324,326,328,330,332,334,336],{"class":35,"line":314},17,[33,316,140],{"class":71},[33,318,319],{"class":99}," b",[33,321,146],{"class":71},[33,323,149],{"class":71},[33,325,253],{"class":75},[33,327,80],{"class":79},[33,329,156],{"class":99},[33,331,87],{"class":79},[33,333,161],{"class":99},[33,335,164],{"class":79},[33,337,338],{"class":39},"\u002F\u002F hidden class: {y, x} — DIFFERENT → can't share inline caches\n",[33,340,342],{"class":35,"line":341},18,[33,343,59],{"emptyLinePlaceholder":58},[33,345,347],{"class":35,"line":346},19,[33,348,349],{"class":39},"\u002F\u002F ❌ Adding properties after construction (causes hidden class transitions)\n",[33,351,353,355,358,360,362,364,366,368,370,372],{"class":35,"line":352},20,[33,354,140],{"class":71},[33,356,357],{"class":99}," p3",[33,359,146],{"class":71},[33,361,149],{"class":71},[33,363,76],{"class":75},[33,365,80],{"class":79},[33,367,156],{"class":99},[33,369,87],{"class":79},[33,371,161],{"class":99},[33,373,374],{"class":79},");\n",[33,376,378,381,383,386,389],{"class":35,"line":377},21,[33,379,380],{"class":79},"p3.z ",[33,382,106],{"class":71},[33,384,385],{"class":99}," 3",[33,387,388],{"class":79},";  ",[33,390,391],{"class":39},"\u002F\u002F hidden class transition: Point{x, y} → Point{x, y, z} (slower for this instance)\n",[33,393,395],{"class":35,"line":394},22,[33,396,397],{"class":39},"\u002F\u002F Future Point instances still use Point{x, y} — p3 has a different (slower) hidden class.\n",[33,399,401],{"class":35,"line":400},23,[33,402,59],{"emptyLinePlaceholder":58},[33,404,406],{"class":35,"line":405},24,[33,407,408],{"class":39},"\u002F\u002F ── Inline caches: V8 remembers the hidden class at property access sites ──\n",[33,410,412,414,417,419,422,424,427],{"class":35,"line":411},25,[33,413,72],{"class":71},[33,415,416],{"class":75}," getX",[33,418,80],{"class":79},[33,420,421],{"class":83},"obj",[33,423,226],{"class":79},[33,425,426],{"class":71},"return",[33,428,429],{"class":79}," obj.x; }\n",[33,431,433,436,439,441,443,445,448],{"class":35,"line":432},26,[33,434,435],{"class":75},"getX",[33,437,438],{"class":79},"(p1); ",[33,440,435],{"class":75},[33,442,438],{"class":79},[33,444,435],{"class":75},[33,446,447],{"class":79},"(p1);  ",[33,449,450],{"class":39},"\u002F\u002F V8 caches: \"obj is Point{x,y}, x is at offset N\"\n",[33,452,454,456,459],{"class":35,"line":453},27,[33,455,435],{"class":75},[33,457,458],{"class":79},"(p2);  ",[33,460,461],{"class":39},"\u002F\u002F same hidden class → cache hit → fast\n",[33,463,465,467,470],{"class":35,"line":464},28,[33,466,435],{"class":75},[33,468,469],{"class":79},"(b);   ",[33,471,472],{"class":39},"\u002F\u002F different hidden class → cache miss → deoptimize → re-cache\n",[33,474,476],{"class":35,"line":475},29,[33,477,59],{"emptyLinePlaceholder":58},[33,479,481],{"class":35,"line":480},30,[33,482,483],{"class":39},"\u002F\u002F ── Best practices for hidden class stability ──\n",[33,485,487],{"class":35,"line":486},31,[33,488,489],{"class":39},"\u002F\u002F 1. Declare all properties in the constructor (in the same order for all instances)\n",[33,491,493],{"class":35,"line":492},32,[33,494,495],{"class":39},"\u002F\u002F 2. Don't add properties after construction (use a fixed set of properties)\n",[33,497,499],{"class":35,"line":498},33,[33,500,501],{"class":39},"\u002F\u002F 3. Don't delete properties (causes transitions) — use null\u002Fundefined instead\n",[33,503,505],{"class":35,"line":504},34,[33,506,507],{"class":39},"\u002F\u002F 4. Avoid polymorphic call sites (same function called with different hidden classes)\n",[15,509,511],{"id":510},"closure-induced-memory-leaks","Closure-Induced Memory Leaks",[20,513,514],{"language":22},[24,515,517],{"className":26,"code":516,"language":22,"meta":28,"style":28},"\u002F\u002F ── Closures keep captured variables alive — can cause leaks ──\n\n\u002F\u002F ❌ LEAK: closure captures the entire large array (even though only .length is used)\nfunction createLeak() {\n    const hugeArray = new Array(1_000_000).fill(\"*\");\n    return () => hugeArray.length;  \u002F\u002F closure captures hugeArray → stays alive\n}\nconst leak = createLeak();  \u002F\u002F hugeArray (8MB) stays alive as long as `leak` exists\n\n\u002F\u002F ✅ FIX: extract the value, let the large object be GC'd\nfunction createSafe() {\n    const hugeArray = new Array(1_000_000).fill(\"*\");\n    const length = hugeArray.length;  \u002F\u002F extract the value (a number)\n    return () => length;  \u002F\u002F closure captures `length` (a number), not `hugeArray`\n    \u002F\u002F hugeArray is no longer referenced → GC'd after createSafe returns\n}\n\n\u002F\u002F ── Detached DOM elements (closure + DOM = leak) ──\nfunction setupLeak() {\n    const element = document.querySelector(\"#removed\");\n    const heavyData = { \u002F* large object *\u002F };\n    element.addEventListener(\"click\", () => {\n        console.log(heavyData, element);  \u002F\u002F closure captures heavyData AND element\n    });\n    document.body.removeChild(element);  \u002F\u002F remove from DOM\n    \u002F\u002F The element and heavyData are still alive (closure holds references) → LEAK\n}\n\n\u002F\u002F ✅ FIX: use AbortController for clean listener removal\nfunction setupClean() {\n    const controller = new AbortController();\n    const element = document.querySelector(\"#target\");\n    element.addEventListener(\"click\", handler, { signal: controller.signal });\n    return () => controller.abort();  \u002F\u002F cleanup: removes listener → element can be GC'd\n}\n\n\u002F\u002F ── Timer leaks (setInterval keeps running) ──\nfunction timerLeak() {\n    setInterval(() => {\n        console.log(\"running\");  \u002F\u002F runs forever — keeps the closure alive\n    }, 1000);\n}\n\u002F\u002F ✅ FIX: store the ID and clear it\nfunction cleanTimer() {\n    const id = setInterval(() => console.log(\"running\"), 1000);\n    return () => clearInterval(id);  \u002F\u002F cleanup function\n}\n",[30,518,519,524,528,533,543,577,599,603,620,624,629,638,664,682,696,701,705,709,714,723,745,763,784,798,803,817,822,826,830,835,844,861,880,893,912,917,922,928,938,951,968,979,984,990,1000,1033,1051],{"__ignoreMap":28},[33,520,521],{"class":35,"line":36},[33,522,523],{"class":39},"\u002F\u002F ── Closures keep captured variables alive — can cause leaks ──\n",[33,525,526],{"class":35,"line":43},[33,527,59],{"emptyLinePlaceholder":58},[33,529,530],{"class":35,"line":49},[33,531,532],{"class":39},"\u002F\u002F ❌ LEAK: closure captures the entire large array (even though only .length is used)\n",[33,534,535,537,540],{"class":35,"line":55},[33,536,72],{"class":71},[33,538,539],{"class":75}," createLeak",[33,541,542],{"class":79},"() {\n",[33,544,545,548,551,553,555,558,560,563,566,569,571,575],{"class":35,"line":62},[33,546,547],{"class":71},"    const",[33,549,550],{"class":99}," hugeArray",[33,552,146],{"class":71},[33,554,149],{"class":71},[33,556,557],{"class":75}," Array",[33,559,80],{"class":79},[33,561,562],{"class":99},"1_000_000",[33,564,565],{"class":79},").",[33,567,568],{"class":75},"fill",[33,570,80],{"class":79},[33,572,574],{"class":573},"sJ6F3","\"*\"",[33,576,374],{"class":79},[33,578,579,582,585,588,591,594,596],{"class":35,"line":68},[33,580,581],{"class":71},"    return",[33,583,584],{"class":79}," () ",[33,586,587],{"class":71},"=>",[33,589,590],{"class":79}," hugeArray.",[33,592,593],{"class":99},"length",[33,595,388],{"class":79},[33,597,598],{"class":39},"\u002F\u002F closure captures hugeArray → stays alive\n",[33,600,601],{"class":35,"line":96},[33,602,134],{"class":79},[33,604,605,607,610,612,614,617],{"class":35,"line":115},[33,606,140],{"class":71},[33,608,609],{"class":99}," leak",[33,611,146],{"class":71},[33,613,539],{"class":75},[33,615,616],{"class":79},"();  ",[33,618,619],{"class":39},"\u002F\u002F hugeArray (8MB) stays alive as long as `leak` exists\n",[33,621,622],{"class":35,"line":131},[33,623,59],{"emptyLinePlaceholder":58},[33,625,626],{"class":35,"line":137},[33,627,628],{"class":39},"\u002F\u002F ✅ FIX: extract the value, let the large object be GC'd\n",[33,630,631,633,636],{"class":35,"line":170},[33,632,72],{"class":71},[33,634,635],{"class":75}," createSafe",[33,637,542],{"class":79},[33,639,640,642,644,646,648,650,652,654,656,658,660,662],{"class":35,"line":199},[33,641,547],{"class":71},[33,643,550],{"class":99},[33,645,146],{"class":71},[33,647,149],{"class":71},[33,649,557],{"class":75},[33,651,80],{"class":79},[33,653,562],{"class":99},[33,655,565],{"class":79},[33,657,568],{"class":75},[33,659,80],{"class":79},[33,661,574],{"class":573},[33,663,374],{"class":79},[33,665,666,668,671,673,675,677,679],{"class":35,"line":204},[33,667,547],{"class":71},[33,669,670],{"class":99}," length",[33,672,146],{"class":71},[33,674,590],{"class":79},[33,676,593],{"class":99},[33,678,388],{"class":79},[33,680,681],{"class":39},"\u002F\u002F extract the value (a number)\n",[33,683,684,686,688,690,693],{"class":35,"line":210},[33,685,581],{"class":71},[33,687,584],{"class":79},[33,689,587],{"class":71},[33,691,692],{"class":79}," length;  ",[33,694,695],{"class":39},"\u002F\u002F closure captures `length` (a number), not `hugeArray`\n",[33,697,698],{"class":35,"line":248},[33,699,700],{"class":39},"    \u002F\u002F hugeArray is no longer referenced → GC'd after createSafe returns\n",[33,702,703],{"class":35,"line":287},[33,704,134],{"class":79},[33,706,707],{"class":35,"line":314},[33,708,59],{"emptyLinePlaceholder":58},[33,710,711],{"class":35,"line":341},[33,712,713],{"class":39},"\u002F\u002F ── Detached DOM elements (closure + DOM = leak) ──\n",[33,715,716,718,721],{"class":35,"line":346},[33,717,72],{"class":71},[33,719,720],{"class":75}," setupLeak",[33,722,542],{"class":79},[33,724,725,727,730,732,735,738,740,743],{"class":35,"line":352},[33,726,547],{"class":71},[33,728,729],{"class":99}," element",[33,731,146],{"class":71},[33,733,734],{"class":79}," document.",[33,736,737],{"class":75},"querySelector",[33,739,80],{"class":79},[33,741,742],{"class":573},"\"#removed\"",[33,744,374],{"class":79},[33,746,747,749,752,754,757,760],{"class":35,"line":377},[33,748,547],{"class":71},[33,750,751],{"class":99}," heavyData",[33,753,146],{"class":71},[33,755,756],{"class":79}," { ",[33,758,759],{"class":39},"\u002F* large object *\u002F",[33,761,762],{"class":79}," };\n",[33,764,765,768,771,773,776,779,781],{"class":35,"line":394},[33,766,767],{"class":79},"    element.",[33,769,770],{"class":75},"addEventListener",[33,772,80],{"class":79},[33,774,775],{"class":573},"\"click\"",[33,777,778],{"class":79},", () ",[33,780,587],{"class":71},[33,782,783],{"class":79}," {\n",[33,785,786,789,792,795],{"class":35,"line":400},[33,787,788],{"class":79},"        console.",[33,790,791],{"class":75},"log",[33,793,794],{"class":79},"(heavyData, element);  ",[33,796,797],{"class":39},"\u002F\u002F closure captures heavyData AND element\n",[33,799,800],{"class":35,"line":405},[33,801,802],{"class":79},"    });\n",[33,804,805,808,811,814],{"class":35,"line":411},[33,806,807],{"class":79},"    document.body.",[33,809,810],{"class":75},"removeChild",[33,812,813],{"class":79},"(element);  ",[33,815,816],{"class":39},"\u002F\u002F remove from DOM\n",[33,818,819],{"class":35,"line":432},[33,820,821],{"class":39},"    \u002F\u002F The element and heavyData are still alive (closure holds references) → LEAK\n",[33,823,824],{"class":35,"line":453},[33,825,134],{"class":79},[33,827,828],{"class":35,"line":464},[33,829,59],{"emptyLinePlaceholder":58},[33,831,832],{"class":35,"line":475},[33,833,834],{"class":39},"\u002F\u002F ✅ FIX: use AbortController for clean listener removal\n",[33,836,837,839,842],{"class":35,"line":480},[33,838,72],{"class":71},[33,840,841],{"class":75}," setupClean",[33,843,542],{"class":79},[33,845,846,848,851,853,855,858],{"class":35,"line":486},[33,847,547],{"class":71},[33,849,850],{"class":99}," controller",[33,852,146],{"class":71},[33,854,149],{"class":71},[33,856,857],{"class":75}," AbortController",[33,859,860],{"class":79},"();\n",[33,862,863,865,867,869,871,873,875,878],{"class":35,"line":492},[33,864,547],{"class":71},[33,866,729],{"class":99},[33,868,146],{"class":71},[33,870,734],{"class":79},[33,872,737],{"class":75},[33,874,80],{"class":79},[33,876,877],{"class":573},"\"#target\"",[33,879,374],{"class":79},[33,881,882,884,886,888,890],{"class":35,"line":498},[33,883,767],{"class":79},[33,885,770],{"class":75},[33,887,80],{"class":79},[33,889,775],{"class":573},[33,891,892],{"class":79},", handler, { signal: controller.signal });\n",[33,894,895,897,899,901,904,907,909],{"class":35,"line":504},[33,896,581],{"class":71},[33,898,584],{"class":79},[33,900,587],{"class":71},[33,902,903],{"class":79}," controller.",[33,905,906],{"class":75},"abort",[33,908,616],{"class":79},[33,910,911],{"class":39},"\u002F\u002F cleanup: removes listener → element can be GC'd\n",[33,913,915],{"class":35,"line":914},35,[33,916,134],{"class":79},[33,918,920],{"class":35,"line":919},36,[33,921,59],{"emptyLinePlaceholder":58},[33,923,925],{"class":35,"line":924},37,[33,926,927],{"class":39},"\u002F\u002F ── Timer leaks (setInterval keeps running) ──\n",[33,929,931,933,936],{"class":35,"line":930},38,[33,932,72],{"class":71},[33,934,935],{"class":75}," timerLeak",[33,937,542],{"class":79},[33,939,941,944,947,949],{"class":35,"line":940},39,[33,942,943],{"class":75},"    setInterval",[33,945,946],{"class":79},"(() ",[33,948,587],{"class":71},[33,950,783],{"class":79},[33,952,954,956,958,960,963,965],{"class":35,"line":953},40,[33,955,788],{"class":79},[33,957,791],{"class":75},[33,959,80],{"class":79},[33,961,962],{"class":573},"\"running\"",[33,964,164],{"class":79},[33,966,967],{"class":39},"\u002F\u002F runs forever — keeps the closure alive\n",[33,969,971,974,977],{"class":35,"line":970},41,[33,972,973],{"class":79},"    }, ",[33,975,976],{"class":99},"1000",[33,978,374],{"class":79},[33,980,982],{"class":35,"line":981},42,[33,983,134],{"class":79},[33,985,987],{"class":35,"line":986},43,[33,988,989],{"class":39},"\u002F\u002F ✅ FIX: store the ID and clear it\n",[33,991,993,995,998],{"class":35,"line":992},44,[33,994,72],{"class":71},[33,996,997],{"class":75}," cleanTimer",[33,999,542],{"class":79},[33,1001,1003,1005,1008,1010,1013,1015,1017,1020,1022,1024,1026,1029,1031],{"class":35,"line":1002},45,[33,1004,547],{"class":71},[33,1006,1007],{"class":99}," id",[33,1009,146],{"class":71},[33,1011,1012],{"class":75}," setInterval",[33,1014,946],{"class":79},[33,1016,587],{"class":71},[33,1018,1019],{"class":79}," console.",[33,1021,791],{"class":75},[33,1023,80],{"class":79},[33,1025,962],{"class":573},[33,1027,1028],{"class":79},"), ",[33,1030,976],{"class":99},[33,1032,374],{"class":79},[33,1034,1036,1038,1040,1042,1045,1048],{"class":35,"line":1035},46,[33,1037,581],{"class":71},[33,1039,584],{"class":79},[33,1041,587],{"class":71},[33,1043,1044],{"class":75}," clearInterval",[33,1046,1047],{"class":79},"(id);  ",[33,1049,1050],{"class":39},"\u002F\u002F cleanup function\n",[33,1052,1054],{"class":35,"line":1053},47,[33,1055,134],{"class":79},[15,1057,1059,1060],{"id":1058},"benchmarking-with-performancenow","Benchmarking with ",[30,1061,1062],{},"performance.now",[20,1064,1065],{"language":22},[24,1066,1068],{"className":26,"code":1067,"language":22,"meta":28,"style":28},"\u002F\u002F ── performance.now: high-resolution monotonic clock (sub-millisecond) ──\nfunction benchmark(fn, iterations = 10000) {\n    \u002F\u002F Warm up (let V8 optimize the function)\n    for (let i = 0; i \u003C 1000; i++) fn();\n\n    const start = performance.now();\n    for (let i = 0; i \u003C iterations; i++) fn();\n    const elapsed = performance.now() - start;\n    return { elapsed, perOp: elapsed \u002F iterations };\n}\n\nconst { perOp } = benchmark(() => {\n    \u002F\u002F code to measure\n    [1, 2, 3].map(x => x * 2);\n});\nconsole.log(`${perOp.toFixed(4)}ms per operation`);\n\n\u002F\u002F ── Compare two implementations ──\nfunction compare(label1, fn1, label2, fn2, iterations = 100000) {\n    \u002F\u002F Warm up both\n    for (let i = 0; i \u003C 1000; i++) { fn1(); fn2(); }\n\n    const t1 = benchmark(fn1, iterations).perOp;\n    const t2 = benchmark(fn2, iterations).perOp;\n    console.log(`${label1}: ${t1.toFixed(6)}ms`);\n    console.log(`${label2}: ${t2.toFixed(6)}ms`);\n    console.log(`ratio: ${(t1 \u002F t2).toFixed(2)}x`);\n}\n\n\u002F\u002F ── Example: parameter expansion vs spread ──\ncompare(\n    \"spread\", () => Math.max(...[1, 2, 3, 4, 5]),\n    \"apply\",  () => Math.max.apply(null, [1, 2, 3, 4, 5]),\n);\n\n\u002F\u002F ── ⚠️ Benchmark pitfalls ──\n\u002F\u002F 1. Warm up first (V8 optimizes after repeated calls — don't measure cold code)\n\u002F\u002F 2. Run enough iterations (too few → noise dominates)\n\u002F\u002F 3. Don't measure dead code (V8 might eliminate unused results — use the result)\n\u002F\u002F 4. Beware of GC pauses (run multiple times, take the median)\n\u002F\u002F 5. Use `performance.now()` (not `Date.now()` — low resolution, not monotonic)\n",[30,1069,1070,1075,1099,1104,1145,1149,1166,1195,1217,1230,1234,1238,1260,1265,1304,1309,1341,1345,1350,1388,1393,1429,1433,1447,1461,1496,1527,1562,1566,1570,1575,1583,1628,1672,1676,1680,1685,1690,1695,1700,1705],{"__ignoreMap":28},[33,1071,1072],{"class":35,"line":36},[33,1073,1074],{"class":39},"\u002F\u002F ── performance.now: high-resolution monotonic clock (sub-millisecond) ──\n",[33,1076,1077,1079,1082,1084,1087,1089,1092,1094,1097],{"class":35,"line":43},[33,1078,72],{"class":71},[33,1080,1081],{"class":75}," benchmark",[33,1083,80],{"class":79},[33,1085,1086],{"class":83},"fn",[33,1088,87],{"class":79},[33,1090,1091],{"class":83},"iterations",[33,1093,146],{"class":71},[33,1095,1096],{"class":99}," 10000",[33,1098,93],{"class":79},[33,1100,1101],{"class":35,"line":49},[33,1102,1103],{"class":39},"    \u002F\u002F Warm up (let V8 optimize the function)\n",[33,1105,1106,1109,1112,1115,1118,1120,1123,1126,1129,1132,1135,1138,1141,1143],{"class":35,"line":55},[33,1107,1108],{"class":71},"    for",[33,1110,1111],{"class":79}," (",[33,1113,1114],{"class":71},"let",[33,1116,1117],{"class":79}," i ",[33,1119,106],{"class":71},[33,1121,1122],{"class":99}," 0",[33,1124,1125],{"class":79},"; i ",[33,1127,1128],{"class":71},"\u003C",[33,1130,1131],{"class":99}," 1000",[33,1133,1134],{"class":79},"; i",[33,1136,1137],{"class":71},"++",[33,1139,1140],{"class":79},") ",[33,1142,1086],{"class":75},[33,1144,860],{"class":79},[33,1146,1147],{"class":35,"line":62},[33,1148,59],{"emptyLinePlaceholder":58},[33,1150,1151,1153,1156,1158,1161,1164],{"class":35,"line":68},[33,1152,547],{"class":71},[33,1154,1155],{"class":99}," start",[33,1157,146],{"class":71},[33,1159,1160],{"class":79}," performance.",[33,1162,1163],{"class":75},"now",[33,1165,860],{"class":79},[33,1167,1168,1170,1172,1174,1176,1178,1180,1182,1184,1187,1189,1191,1193],{"class":35,"line":96},[33,1169,1108],{"class":71},[33,1171,1111],{"class":79},[33,1173,1114],{"class":71},[33,1175,1117],{"class":79},[33,1177,106],{"class":71},[33,1179,1122],{"class":99},[33,1181,1125],{"class":79},[33,1183,1128],{"class":71},[33,1185,1186],{"class":79}," iterations; i",[33,1188,1137],{"class":71},[33,1190,1140],{"class":79},[33,1192,1086],{"class":75},[33,1194,860],{"class":79},[33,1196,1197,1199,1202,1204,1206,1208,1211,1214],{"class":35,"line":115},[33,1198,547],{"class":71},[33,1200,1201],{"class":99}," elapsed",[33,1203,146],{"class":71},[33,1205,1160],{"class":79},[33,1207,1163],{"class":75},[33,1209,1210],{"class":79},"() ",[33,1212,1213],{"class":71},"-",[33,1215,1216],{"class":79}," start;\n",[33,1218,1219,1221,1224,1227],{"class":35,"line":131},[33,1220,581],{"class":71},[33,1222,1223],{"class":79}," { elapsed, perOp: elapsed ",[33,1225,1226],{"class":71},"\u002F",[33,1228,1229],{"class":79}," iterations };\n",[33,1231,1232],{"class":35,"line":137},[33,1233,134],{"class":79},[33,1235,1236],{"class":35,"line":170},[33,1237,59],{"emptyLinePlaceholder":58},[33,1239,1240,1242,1244,1247,1250,1252,1254,1256,1258],{"class":35,"line":199},[33,1241,140],{"class":71},[33,1243,756],{"class":79},[33,1245,1246],{"class":99},"perOp",[33,1248,1249],{"class":79}," } ",[33,1251,106],{"class":71},[33,1253,1081],{"class":75},[33,1255,946],{"class":79},[33,1257,587],{"class":71},[33,1259,783],{"class":79},[33,1261,1262],{"class":35,"line":204},[33,1263,1264],{"class":39},"    \u002F\u002F code to measure\n",[33,1266,1267,1270,1272,1274,1276,1278,1280,1283,1286,1288,1290,1293,1296,1299,1302],{"class":35,"line":210},[33,1268,1269],{"class":79},"    [",[33,1271,156],{"class":99},[33,1273,87],{"class":79},[33,1275,161],{"class":99},[33,1277,87],{"class":79},[33,1279,186],{"class":99},[33,1281,1282],{"class":79},"].",[33,1284,1285],{"class":75},"map",[33,1287,80],{"class":79},[33,1289,84],{"class":83},[33,1291,1292],{"class":71}," =>",[33,1294,1295],{"class":79}," x ",[33,1297,1298],{"class":71},"*",[33,1300,1301],{"class":99}," 2",[33,1303,374],{"class":79},[33,1305,1306],{"class":35,"line":248},[33,1307,1308],{"class":79},"});\n",[33,1310,1311,1314,1316,1318,1321,1323,1326,1329,1331,1333,1336,1339],{"class":35,"line":287},[33,1312,1313],{"class":79},"console.",[33,1315,791],{"class":75},[33,1317,80],{"class":79},[33,1319,1320],{"class":573},"`${",[33,1322,1246],{"class":79},[33,1324,1325],{"class":573},".",[33,1327,1328],{"class":75},"toFixed",[33,1330,80],{"class":573},[33,1332,191],{"class":99},[33,1334,1335],{"class":573},")",[33,1337,1338],{"class":573},"}ms per operation`",[33,1340,374],{"class":79},[33,1342,1343],{"class":35,"line":314},[33,1344,59],{"emptyLinePlaceholder":58},[33,1346,1347],{"class":35,"line":341},[33,1348,1349],{"class":39},"\u002F\u002F ── Compare two implementations ──\n",[33,1351,1352,1354,1357,1359,1362,1364,1367,1369,1372,1374,1377,1379,1381,1383,1386],{"class":35,"line":346},[33,1353,72],{"class":71},[33,1355,1356],{"class":75}," compare",[33,1358,80],{"class":79},[33,1360,1361],{"class":83},"label1",[33,1363,87],{"class":79},[33,1365,1366],{"class":83},"fn1",[33,1368,87],{"class":79},[33,1370,1371],{"class":83},"label2",[33,1373,87],{"class":79},[33,1375,1376],{"class":83},"fn2",[33,1378,87],{"class":79},[33,1380,1091],{"class":83},[33,1382,146],{"class":71},[33,1384,1385],{"class":99}," 100000",[33,1387,93],{"class":79},[33,1389,1390],{"class":35,"line":352},[33,1391,1392],{"class":39},"    \u002F\u002F Warm up both\n",[33,1394,1395,1397,1399,1401,1403,1405,1407,1409,1411,1413,1415,1417,1419,1421,1424,1426],{"class":35,"line":377},[33,1396,1108],{"class":71},[33,1398,1111],{"class":79},[33,1400,1114],{"class":71},[33,1402,1117],{"class":79},[33,1404,106],{"class":71},[33,1406,1122],{"class":99},[33,1408,1125],{"class":79},[33,1410,1128],{"class":71},[33,1412,1131],{"class":99},[33,1414,1134],{"class":79},[33,1416,1137],{"class":71},[33,1418,226],{"class":79},[33,1420,1366],{"class":75},[33,1422,1423],{"class":79},"(); ",[33,1425,1376],{"class":75},[33,1427,1428],{"class":79},"(); }\n",[33,1430,1431],{"class":35,"line":394},[33,1432,59],{"emptyLinePlaceholder":58},[33,1434,1435,1437,1440,1442,1444],{"class":35,"line":400},[33,1436,547],{"class":71},[33,1438,1439],{"class":99}," t1",[33,1441,146],{"class":71},[33,1443,1081],{"class":75},[33,1445,1446],{"class":79},"(fn1, iterations).perOp;\n",[33,1448,1449,1451,1454,1456,1458],{"class":35,"line":405},[33,1450,547],{"class":71},[33,1452,1453],{"class":99}," t2",[33,1455,146],{"class":71},[33,1457,1081],{"class":75},[33,1459,1460],{"class":79},"(fn2, iterations).perOp;\n",[33,1462,1463,1466,1468,1470,1472,1474,1477,1480,1482,1484,1486,1489,1491,1494],{"class":35,"line":411},[33,1464,1465],{"class":79},"    console.",[33,1467,791],{"class":75},[33,1469,80],{"class":79},[33,1471,1320],{"class":573},[33,1473,1361],{"class":79},[33,1475,1476],{"class":573},"}: ${",[33,1478,1479],{"class":79},"t1",[33,1481,1325],{"class":573},[33,1483,1328],{"class":75},[33,1485,80],{"class":573},[33,1487,1488],{"class":99},"6",[33,1490,1335],{"class":573},[33,1492,1493],{"class":573},"}ms`",[33,1495,374],{"class":79},[33,1497,1498,1500,1502,1504,1506,1508,1510,1513,1515,1517,1519,1521,1523,1525],{"class":35,"line":432},[33,1499,1465],{"class":79},[33,1501,791],{"class":75},[33,1503,80],{"class":79},[33,1505,1320],{"class":573},[33,1507,1371],{"class":79},[33,1509,1476],{"class":573},[33,1511,1512],{"class":79},"t2",[33,1514,1325],{"class":573},[33,1516,1328],{"class":75},[33,1518,80],{"class":573},[33,1520,1488],{"class":99},[33,1522,1335],{"class":573},[33,1524,1493],{"class":573},[33,1526,374],{"class":79},[33,1528,1529,1531,1533,1535,1538,1540,1542,1545,1547,1549,1551,1553,1555,1557,1560],{"class":35,"line":453},[33,1530,1465],{"class":79},[33,1532,791],{"class":75},[33,1534,80],{"class":79},[33,1536,1537],{"class":573},"`ratio: ${",[33,1539,80],{"class":573},[33,1541,1479],{"class":79},[33,1543,1544],{"class":71}," \u002F",[33,1546,1453],{"class":79},[33,1548,565],{"class":573},[33,1550,1328],{"class":75},[33,1552,80],{"class":573},[33,1554,161],{"class":99},[33,1556,1335],{"class":573},[33,1558,1559],{"class":573},"}x`",[33,1561,374],{"class":79},[33,1563,1564],{"class":35,"line":464},[33,1565,134],{"class":79},[33,1567,1568],{"class":35,"line":475},[33,1569,59],{"emptyLinePlaceholder":58},[33,1571,1572],{"class":35,"line":480},[33,1573,1574],{"class":39},"\u002F\u002F ── Example: parameter expansion vs spread ──\n",[33,1576,1577,1580],{"class":35,"line":486},[33,1578,1579],{"class":75},"compare",[33,1581,1582],{"class":79},"(\n",[33,1584,1585,1588,1590,1592,1595,1598,1600,1603,1606,1608,1610,1612,1614,1616,1618,1620,1622,1625],{"class":35,"line":492},[33,1586,1587],{"class":573},"    \"spread\"",[33,1589,778],{"class":79},[33,1591,587],{"class":71},[33,1593,1594],{"class":79}," Math.",[33,1596,1597],{"class":75},"max",[33,1599,80],{"class":79},[33,1601,1602],{"class":71},"...",[33,1604,1605],{"class":79},"[",[33,1607,156],{"class":99},[33,1609,87],{"class":79},[33,1611,161],{"class":99},[33,1613,87],{"class":79},[33,1615,186],{"class":99},[33,1617,87],{"class":79},[33,1619,191],{"class":99},[33,1621,87],{"class":79},[33,1623,1624],{"class":99},"5",[33,1626,1627],{"class":79},"]),\n",[33,1629,1630,1633,1636,1638,1641,1644,1646,1649,1652,1654,1656,1658,1660,1662,1664,1666,1668,1670],{"class":35,"line":498},[33,1631,1632],{"class":573},"    \"apply\"",[33,1634,1635],{"class":79},",  () ",[33,1637,587],{"class":71},[33,1639,1640],{"class":79}," Math.max.",[33,1642,1643],{"class":75},"apply",[33,1645,80],{"class":79},[33,1647,1648],{"class":99},"null",[33,1650,1651],{"class":79},", [",[33,1653,156],{"class":99},[33,1655,87],{"class":79},[33,1657,161],{"class":99},[33,1659,87],{"class":79},[33,1661,186],{"class":99},[33,1663,87],{"class":79},[33,1665,191],{"class":99},[33,1667,87],{"class":79},[33,1669,1624],{"class":99},[33,1671,1627],{"class":79},[33,1673,1674],{"class":35,"line":504},[33,1675,374],{"class":79},[33,1677,1678],{"class":35,"line":914},[33,1679,59],{"emptyLinePlaceholder":58},[33,1681,1682],{"class":35,"line":919},[33,1683,1684],{"class":39},"\u002F\u002F ── ⚠️ Benchmark pitfalls ──\n",[33,1686,1687],{"class":35,"line":924},[33,1688,1689],{"class":39},"\u002F\u002F 1. Warm up first (V8 optimizes after repeated calls — don't measure cold code)\n",[33,1691,1692],{"class":35,"line":930},[33,1693,1694],{"class":39},"\u002F\u002F 2. Run enough iterations (too few → noise dominates)\n",[33,1696,1697],{"class":35,"line":940},[33,1698,1699],{"class":39},"\u002F\u002F 3. Don't measure dead code (V8 might eliminate unused results — use the result)\n",[33,1701,1702],{"class":35,"line":953},[33,1703,1704],{"class":39},"\u002F\u002F 4. Beware of GC pauses (run multiple times, take the median)\n",[33,1706,1707],{"class":35,"line":970},[33,1708,1709],{"class":39},"\u002F\u002F 5. Use `performance.now()` (not `Date.now()` — low resolution, not monotonic)\n",[15,1711,1713,1714,1717],{"id":1712},"deep-clone-performance-structuredclone-vs-json","Deep Clone Performance: ",[30,1715,1716],{},"structuredClone"," vs JSON",[20,1719,1720],{"language":22},[24,1721,1723],{"className":26,"code":1722,"language":22,"meta":28,"style":28},"\u002F\u002F ── Deep clone methods (ranked by performance and capability) ──\n\n\u002F\u002F Method 1: structuredClone (modern, handles most types — NOT functions)\nconst clone1 = structuredClone(original);\n\u002F\u002F Handles: nested objects, arrays, Date, RegExp, Map, Set, ArrayBuffer, typed arrays, circular refs\n\u002F\u002F Fails: functions, DOM nodes, Symbols, class instances (loses prototype)\n\u002F\u002F Performance: fast (native C++ implementation)\n\n\u002F\u002F Method 2: JSON.parse(JSON.stringify()) (legacy — lossy)\nconst clone2 = JSON.parse(JSON.stringify(original));\n\u002F\u002F Handles: plain objects, arrays, strings, numbers, booleans, null\n\u002F\u002F Loses: undefined, Date → string, NaN → null, Map\u002FSet → {}, functions → omitted, BigInt → throws\n\u002F\u002F Performance: slower than structuredClone (string serialization overhead)\n\n\u002F\u002F Method 3: manual recursive clone (full control, handles custom types)\nfunction deepClone(obj, cache = new WeakMap()) {\n    if (obj === null || typeof obj !== \"object\") return obj;\n    if (obj instanceof Date) return new Date(obj);\n    if (obj instanceof RegExp) return new RegExp(obj);\n    if (obj instanceof Map) return new Map([...obj].map(([k, v]) => [deepClone(k, cache), deepClone(v, cache)]));\n    if (cache.has(obj)) return cache.get(obj);  \u002F\u002F circular reference guard\n    const clone = Array.isArray(obj) ? [] : Object.create(Object.getPrototypeOf(obj));\n    cache.set(obj, clone);\n    for (const key of Reflect.ownKeys(obj)) {\n        clone[key] = deepClone(obj[key], cache);\n    }\n    return clone;\n}\n\n\u002F\u002F ── Benchmark: structuredClone vs JSON vs manual ──\nconst data = { users: Array.from({ length: 1000 }, (_, i) => ({ id: i, name: `User${i}` })) };\n\u002F\u002F structuredClone(data): ~1ms (fastest for complex types)\n\u002F\u002F JSON.parse(JSON.stringify(data)): ~3ms (slower, lossy)\n\u002F\u002F deepClone(data): ~8ms (slowest, but handles everything)\n",[30,1724,1725,1730,1734,1739,1754,1759,1764,1769,1773,1778,1808,1813,1818,1823,1827,1832,1858,1894,1917,1938,1997,2024,2066,2077,2100,2112,2117,2124,2128,2132,2137,2186,2191,2196],{"__ignoreMap":28},[33,1726,1727],{"class":35,"line":36},[33,1728,1729],{"class":39},"\u002F\u002F ── Deep clone methods (ranked by performance and capability) ──\n",[33,1731,1732],{"class":35,"line":43},[33,1733,59],{"emptyLinePlaceholder":58},[33,1735,1736],{"class":35,"line":49},[33,1737,1738],{"class":39},"\u002F\u002F Method 1: structuredClone (modern, handles most types — NOT functions)\n",[33,1740,1741,1743,1746,1748,1751],{"class":35,"line":55},[33,1742,140],{"class":71},[33,1744,1745],{"class":99}," clone1",[33,1747,146],{"class":71},[33,1749,1750],{"class":75}," structuredClone",[33,1752,1753],{"class":79},"(original);\n",[33,1755,1756],{"class":35,"line":62},[33,1757,1758],{"class":39},"\u002F\u002F Handles: nested objects, arrays, Date, RegExp, Map, Set, ArrayBuffer, typed arrays, circular refs\n",[33,1760,1761],{"class":35,"line":68},[33,1762,1763],{"class":39},"\u002F\u002F Fails: functions, DOM nodes, Symbols, class instances (loses prototype)\n",[33,1765,1766],{"class":35,"line":96},[33,1767,1768],{"class":39},"\u002F\u002F Performance: fast (native C++ implementation)\n",[33,1770,1771],{"class":35,"line":115},[33,1772,59],{"emptyLinePlaceholder":58},[33,1774,1775],{"class":35,"line":131},[33,1776,1777],{"class":39},"\u002F\u002F Method 2: JSON.parse(JSON.stringify()) (legacy — lossy)\n",[33,1779,1780,1782,1785,1787,1790,1792,1795,1797,1800,1802,1805],{"class":35,"line":137},[33,1781,140],{"class":71},[33,1783,1784],{"class":99}," clone2",[33,1786,146],{"class":71},[33,1788,1789],{"class":99}," JSON",[33,1791,1325],{"class":79},[33,1793,1794],{"class":75},"parse",[33,1796,80],{"class":79},[33,1798,1799],{"class":99},"JSON",[33,1801,1325],{"class":79},[33,1803,1804],{"class":75},"stringify",[33,1806,1807],{"class":79},"(original));\n",[33,1809,1810],{"class":35,"line":170},[33,1811,1812],{"class":39},"\u002F\u002F Handles: plain objects, arrays, strings, numbers, booleans, null\n",[33,1814,1815],{"class":35,"line":199},[33,1816,1817],{"class":39},"\u002F\u002F Loses: undefined, Date → string, NaN → null, Map\u002FSet → {}, functions → omitted, BigInt → throws\n",[33,1819,1820],{"class":35,"line":204},[33,1821,1822],{"class":39},"\u002F\u002F Performance: slower than structuredClone (string serialization overhead)\n",[33,1824,1825],{"class":35,"line":210},[33,1826,59],{"emptyLinePlaceholder":58},[33,1828,1829],{"class":35,"line":248},[33,1830,1831],{"class":39},"\u002F\u002F Method 3: manual recursive clone (full control, handles custom types)\n",[33,1833,1834,1836,1839,1841,1843,1845,1848,1850,1852,1855],{"class":35,"line":287},[33,1835,72],{"class":71},[33,1837,1838],{"class":75}," deepClone",[33,1840,80],{"class":79},[33,1842,421],{"class":83},[33,1844,87],{"class":79},[33,1846,1847],{"class":83},"cache",[33,1849,146],{"class":71},[33,1851,149],{"class":71},[33,1853,1854],{"class":75}," WeakMap",[33,1856,1857],{"class":79},"()) {\n",[33,1859,1860,1863,1866,1869,1872,1875,1878,1881,1884,1887,1889,1891],{"class":35,"line":314},[33,1861,1862],{"class":71},"    if",[33,1864,1865],{"class":79}," (obj ",[33,1867,1868],{"class":71},"===",[33,1870,1871],{"class":99}," null",[33,1873,1874],{"class":71}," ||",[33,1876,1877],{"class":71}," typeof",[33,1879,1880],{"class":79}," obj ",[33,1882,1883],{"class":71},"!==",[33,1885,1886],{"class":573}," \"object\"",[33,1888,1140],{"class":79},[33,1890,426],{"class":71},[33,1892,1893],{"class":79}," obj;\n",[33,1895,1896,1898,1900,1903,1906,1908,1910,1912,1914],{"class":35,"line":341},[33,1897,1862],{"class":71},[33,1899,1865],{"class":79},[33,1901,1902],{"class":71},"instanceof",[33,1904,1905],{"class":75}," Date",[33,1907,1140],{"class":79},[33,1909,426],{"class":71},[33,1911,149],{"class":71},[33,1913,1905],{"class":75},[33,1915,1916],{"class":79},"(obj);\n",[33,1918,1919,1921,1923,1925,1928,1930,1932,1934,1936],{"class":35,"line":346},[33,1920,1862],{"class":71},[33,1922,1865],{"class":79},[33,1924,1902],{"class":71},[33,1926,1927],{"class":75}," RegExp",[33,1929,1140],{"class":79},[33,1931,426],{"class":71},[33,1933,149],{"class":71},[33,1935,1927],{"class":75},[33,1937,1916],{"class":79},[33,1939,1940,1942,1944,1946,1949,1951,1953,1955,1957,1960,1962,1965,1967,1970,1973,1975,1978,1981,1983,1986,1989,1992,1994],{"class":35,"line":352},[33,1941,1862],{"class":71},[33,1943,1865],{"class":79},[33,1945,1902],{"class":71},[33,1947,1948],{"class":75}," Map",[33,1950,1140],{"class":79},[33,1952,426],{"class":71},[33,1954,149],{"class":71},[33,1956,1948],{"class":75},[33,1958,1959],{"class":79},"([",[33,1961,1602],{"class":71},[33,1963,1964],{"class":79},"obj].",[33,1966,1285],{"class":75},[33,1968,1969],{"class":79},"(([",[33,1971,1972],{"class":83},"k",[33,1974,87],{"class":79},[33,1976,1977],{"class":83},"v",[33,1979,1980],{"class":79},"]) ",[33,1982,587],{"class":71},[33,1984,1985],{"class":79}," [",[33,1987,1988],{"class":75},"deepClone",[33,1990,1991],{"class":79},"(k, cache), ",[33,1993,1988],{"class":75},[33,1995,1996],{"class":79},"(v, cache)]));\n",[33,1998,1999,2001,2004,2007,2010,2012,2015,2018,2021],{"class":35,"line":377},[33,2000,1862],{"class":71},[33,2002,2003],{"class":79}," (cache.",[33,2005,2006],{"class":75},"has",[33,2008,2009],{"class":79},"(obj)) ",[33,2011,426],{"class":71},[33,2013,2014],{"class":79}," cache.",[33,2016,2017],{"class":75},"get",[33,2019,2020],{"class":79},"(obj);  ",[33,2022,2023],{"class":39},"\u002F\u002F circular reference guard\n",[33,2025,2026,2028,2031,2033,2036,2039,2042,2045,2048,2051,2054,2057,2060,2063],{"class":35,"line":394},[33,2027,547],{"class":71},[33,2029,2030],{"class":99}," clone",[33,2032,146],{"class":71},[33,2034,2035],{"class":79}," Array.",[33,2037,2038],{"class":75},"isArray",[33,2040,2041],{"class":79},"(obj) ",[33,2043,2044],{"class":71},"?",[33,2046,2047],{"class":79}," [] ",[33,2049,2050],{"class":71},":",[33,2052,2053],{"class":79}," Object.",[33,2055,2056],{"class":75},"create",[33,2058,2059],{"class":79},"(Object.",[33,2061,2062],{"class":75},"getPrototypeOf",[33,2064,2065],{"class":79},"(obj));\n",[33,2067,2068,2071,2074],{"class":35,"line":400},[33,2069,2070],{"class":79},"    cache.",[33,2072,2073],{"class":75},"set",[33,2075,2076],{"class":79},"(obj, clone);\n",[33,2078,2079,2081,2083,2085,2088,2091,2094,2097],{"class":35,"line":405},[33,2080,1108],{"class":71},[33,2082,1111],{"class":79},[33,2084,140],{"class":71},[33,2086,2087],{"class":99}," key",[33,2089,2090],{"class":71}," of",[33,2092,2093],{"class":79}," Reflect.",[33,2095,2096],{"class":75},"ownKeys",[33,2098,2099],{"class":79},"(obj)) {\n",[33,2101,2102,2105,2107,2109],{"class":35,"line":411},[33,2103,2104],{"class":79},"        clone[key] ",[33,2106,106],{"class":71},[33,2108,1838],{"class":75},[33,2110,2111],{"class":79},"(obj[key], cache);\n",[33,2113,2114],{"class":35,"line":432},[33,2115,2116],{"class":79},"    }\n",[33,2118,2119,2121],{"class":35,"line":453},[33,2120,581],{"class":71},[33,2122,2123],{"class":79}," clone;\n",[33,2125,2126],{"class":35,"line":464},[33,2127,134],{"class":79},[33,2129,2130],{"class":35,"line":475},[33,2131,59],{"emptyLinePlaceholder":58},[33,2133,2134],{"class":35,"line":480},[33,2135,2136],{"class":39},"\u002F\u002F ── Benchmark: structuredClone vs JSON vs manual ──\n",[33,2138,2139,2141,2144,2146,2149,2152,2155,2157,2160,2163,2165,2168,2170,2172,2175,2178,2180,2183],{"class":35,"line":486},[33,2140,140],{"class":71},[33,2142,2143],{"class":99}," data",[33,2145,146],{"class":71},[33,2147,2148],{"class":79}," { users: Array.",[33,2150,2151],{"class":75},"from",[33,2153,2154],{"class":79},"({ length: ",[33,2156,976],{"class":99},[33,2158,2159],{"class":79}," }, (",[33,2161,2162],{"class":83},"_",[33,2164,87],{"class":79},[33,2166,2167],{"class":83},"i",[33,2169,1140],{"class":79},[33,2171,587],{"class":71},[33,2173,2174],{"class":79}," ({ id: i, name: ",[33,2176,2177],{"class":573},"`User${",[33,2179,2167],{"class":79},[33,2181,2182],{"class":573},"}`",[33,2184,2185],{"class":79}," })) };\n",[33,2187,2188],{"class":35,"line":492},[33,2189,2190],{"class":39},"\u002F\u002F structuredClone(data): ~1ms (fastest for complex types)\n",[33,2192,2193],{"class":35,"line":498},[33,2194,2195],{"class":39},"\u002F\u002F JSON.parse(JSON.stringify(data)): ~3ms (slower, lossy)\n",[33,2197,2198],{"class":35,"line":504},[33,2199,2200],{"class":39},"\u002F\u002F deepClone(data): ~8ms (slowest, but handles everything)\n",[15,2202,2204],{"id":2203},"lazy-evaluation-and-memoization","Lazy Evaluation and Memoization",[20,2206,2207],{"language":22},[24,2208,2210],{"className":26,"code":2209,"language":22,"meta":28,"style":28},"\u002F\u002F ── Lazy evaluation: compute only when needed ──\n\n\u002F\u002F ── Lazy property (computed on first access) ──\nclass Config {\n    #parsed = null;\n    get data() {\n        if (this.#parsed === null) {\n            this.#parsed = JSON.parse(this.rawJson);  \u002F\u002F parse on first access\n        }\n        return this.#parsed;\n    }\n    constructor(rawJson) { this.rawJson = rawJson; }\n}\nconst config = new Config(rawJson);\n\u002F\u002F config.rawJson is stored, but data isn't parsed until config.data is accessed.\n\u002F\u002F If data is never accessed, the parse never runs (saves CPU).\n\n\u002F\u002F ── Memoization: cache results (same input → cached output) ──\nfunction memoize(fn) {\n    const cache = new Map();\n    return (...args) => {\n        const key = JSON.stringify(args);\n        if (cache.has(key)) return cache.get(key);\n        const result = fn(...args);\n        cache.set(key, result);\n        return result;\n    };\n}\n\nconst expensiveCompute = memoize((n) => {\n    console.log(\"computing...\");  \u002F\u002F only runs on first call with this input\n    return n * 2;\n});\nexpensiveCompute(42);  \u002F\u002F logs \"computing...\", returns 84\nexpensiveCompute(42);  \u002F\u002F returns 84 (cached, no log)\n\n\u002F\u002F ── Lazy range generator (compute on demand, not upfront) ──\nfunction* range(start, end, step = 1) {\n    for (let i = start; i \u003C end; i += step) yield i;\n}\nconst lazyRange = range(0, 1_000_000_000);  \u002F\u002F doesn't create a billion items\nlazyRange.next().value;  \u002F\u002F 0 (computes on demand)\n\u002F\u002F Only computes values as they're consumed — O(1) memory, infinite sequences possible.\n\n\u002F\u002F ── Virtual list (only render visible items) ──\nfunction* visibleItems(items, scrollTop, viewportHeight, itemHeight) {\n    const start = Math.floor(scrollTop \u002F itemHeight);\n    const end = Math.min(start + Math.ceil(viewportHeight \u002F itemHeight), items.length);\n    for (let i = start; i \u003C end; i++) yield { index: i, item: items[i] };\n}\n",[30,2211,2212,2217,2221,2226,2236,2248,2257,2275,2300,2305,2316,2320,2342,2346,2362,2367,2372,2376,2381,2394,2409,2426,2444,2464,2483,2493,2500,2505,2509,2513,2536,2552,2565,2569,2584,2597,2601,2606,2636,2668,2672,2698,2712,2717,2721,2726,2755,2776,2814,2843],{"__ignoreMap":28},[33,2213,2214],{"class":35,"line":36},[33,2215,2216],{"class":39},"\u002F\u002F ── Lazy evaluation: compute only when needed ──\n",[33,2218,2219],{"class":35,"line":43},[33,2220,59],{"emptyLinePlaceholder":58},[33,2222,2223],{"class":35,"line":49},[33,2224,2225],{"class":39},"\u002F\u002F ── Lazy property (computed on first access) ──\n",[33,2227,2228,2231,2234],{"class":35,"line":55},[33,2229,2230],{"class":71},"class",[33,2232,2233],{"class":75}," Config",[33,2235,783],{"class":79},[33,2237,2238,2241,2243,2245],{"class":35,"line":62},[33,2239,2240],{"class":83},"    #parsed",[33,2242,146],{"class":71},[33,2244,1871],{"class":99},[33,2246,2247],{"class":79},";\n",[33,2249,2250,2253,2255],{"class":35,"line":68},[33,2251,2252],{"class":71},"    get",[33,2254,2143],{"class":75},[33,2256,542],{"class":79},[33,2258,2259,2262,2264,2266,2269,2271,2273],{"class":35,"line":96},[33,2260,2261],{"class":71},"        if",[33,2263,1111],{"class":79},[33,2265,229],{"class":99},[33,2267,2268],{"class":79},".#parsed ",[33,2270,1868],{"class":71},[33,2272,1871],{"class":99},[33,2274,93],{"class":79},[33,2276,2277,2280,2282,2284,2286,2288,2290,2292,2294,2297],{"class":35,"line":115},[33,2278,2279],{"class":99},"            this",[33,2281,2268],{"class":79},[33,2283,106],{"class":71},[33,2285,1789],{"class":99},[33,2287,1325],{"class":79},[33,2289,1794],{"class":75},[33,2291,80],{"class":79},[33,2293,229],{"class":99},[33,2295,2296],{"class":79},".rawJson);  ",[33,2298,2299],{"class":39},"\u002F\u002F parse on first access\n",[33,2301,2302],{"class":35,"line":131},[33,2303,2304],{"class":79},"        }\n",[33,2306,2307,2310,2313],{"class":35,"line":137},[33,2308,2309],{"class":71},"        return",[33,2311,2312],{"class":99}," this",[33,2314,2315],{"class":79},".#parsed;\n",[33,2317,2318],{"class":35,"line":170},[33,2319,2116],{"class":79},[33,2321,2322,2325,2327,2330,2332,2334,2337,2339],{"class":35,"line":199},[33,2323,2324],{"class":71},"    constructor",[33,2326,80],{"class":79},[33,2328,2329],{"class":83},"rawJson",[33,2331,226],{"class":79},[33,2333,229],{"class":99},[33,2335,2336],{"class":79},".rawJson ",[33,2338,106],{"class":71},[33,2340,2341],{"class":79}," rawJson; }\n",[33,2343,2344],{"class":35,"line":204},[33,2345,134],{"class":79},[33,2347,2348,2350,2353,2355,2357,2359],{"class":35,"line":210},[33,2349,140],{"class":71},[33,2351,2352],{"class":99}," config",[33,2354,146],{"class":71},[33,2356,149],{"class":71},[33,2358,2233],{"class":75},[33,2360,2361],{"class":79},"(rawJson);\n",[33,2363,2364],{"class":35,"line":248},[33,2365,2366],{"class":39},"\u002F\u002F config.rawJson is stored, but data isn't parsed until config.data is accessed.\n",[33,2368,2369],{"class":35,"line":287},[33,2370,2371],{"class":39},"\u002F\u002F If data is never accessed, the parse never runs (saves CPU).\n",[33,2373,2374],{"class":35,"line":314},[33,2375,59],{"emptyLinePlaceholder":58},[33,2377,2378],{"class":35,"line":341},[33,2379,2380],{"class":39},"\u002F\u002F ── Memoization: cache results (same input → cached output) ──\n",[33,2382,2383,2385,2388,2390,2392],{"class":35,"line":346},[33,2384,72],{"class":71},[33,2386,2387],{"class":75}," memoize",[33,2389,80],{"class":79},[33,2391,1086],{"class":83},[33,2393,93],{"class":79},[33,2395,2396,2398,2401,2403,2405,2407],{"class":35,"line":352},[33,2397,547],{"class":71},[33,2399,2400],{"class":99}," cache",[33,2402,146],{"class":71},[33,2404,149],{"class":71},[33,2406,1948],{"class":75},[33,2408,860],{"class":79},[33,2410,2411,2413,2415,2417,2420,2422,2424],{"class":35,"line":377},[33,2412,581],{"class":71},[33,2414,1111],{"class":79},[33,2416,1602],{"class":71},[33,2418,2419],{"class":83},"args",[33,2421,1140],{"class":79},[33,2423,587],{"class":71},[33,2425,783],{"class":79},[33,2427,2428,2431,2433,2435,2437,2439,2441],{"class":35,"line":394},[33,2429,2430],{"class":71},"        const",[33,2432,2087],{"class":99},[33,2434,146],{"class":71},[33,2436,1789],{"class":99},[33,2438,1325],{"class":79},[33,2440,1804],{"class":75},[33,2442,2443],{"class":79},"(args);\n",[33,2445,2446,2448,2450,2452,2455,2457,2459,2461],{"class":35,"line":400},[33,2447,2261],{"class":71},[33,2449,2003],{"class":79},[33,2451,2006],{"class":75},[33,2453,2454],{"class":79},"(key)) ",[33,2456,426],{"class":71},[33,2458,2014],{"class":79},[33,2460,2017],{"class":75},[33,2462,2463],{"class":79},"(key);\n",[33,2465,2466,2468,2471,2473,2476,2478,2480],{"class":35,"line":405},[33,2467,2430],{"class":71},[33,2469,2470],{"class":99}," result",[33,2472,146],{"class":71},[33,2474,2475],{"class":75}," fn",[33,2477,80],{"class":79},[33,2479,1602],{"class":71},[33,2481,2482],{"class":79},"args);\n",[33,2484,2485,2488,2490],{"class":35,"line":411},[33,2486,2487],{"class":79},"        cache.",[33,2489,2073],{"class":75},[33,2491,2492],{"class":79},"(key, result);\n",[33,2494,2495,2497],{"class":35,"line":432},[33,2496,2309],{"class":71},[33,2498,2499],{"class":79}," result;\n",[33,2501,2502],{"class":35,"line":453},[33,2503,2504],{"class":79},"    };\n",[33,2506,2507],{"class":35,"line":464},[33,2508,134],{"class":79},[33,2510,2511],{"class":35,"line":475},[33,2512,59],{"emptyLinePlaceholder":58},[33,2514,2515,2517,2520,2522,2524,2527,2530,2532,2534],{"class":35,"line":480},[33,2516,140],{"class":71},[33,2518,2519],{"class":99}," expensiveCompute",[33,2521,146],{"class":71},[33,2523,2387],{"class":75},[33,2525,2526],{"class":79},"((",[33,2528,2529],{"class":83},"n",[33,2531,1140],{"class":79},[33,2533,587],{"class":71},[33,2535,783],{"class":79},[33,2537,2538,2540,2542,2544,2547,2549],{"class":35,"line":486},[33,2539,1465],{"class":79},[33,2541,791],{"class":75},[33,2543,80],{"class":79},[33,2545,2546],{"class":573},"\"computing...\"",[33,2548,164],{"class":79},[33,2550,2551],{"class":39},"\u002F\u002F only runs on first call with this input\n",[33,2553,2554,2556,2559,2561,2563],{"class":35,"line":492},[33,2555,581],{"class":71},[33,2557,2558],{"class":79}," n ",[33,2560,1298],{"class":71},[33,2562,1301],{"class":99},[33,2564,2247],{"class":79},[33,2566,2567],{"class":35,"line":498},[33,2568,1308],{"class":79},[33,2570,2571,2574,2576,2579,2581],{"class":35,"line":504},[33,2572,2573],{"class":75},"expensiveCompute",[33,2575,80],{"class":79},[33,2577,2578],{"class":99},"42",[33,2580,164],{"class":79},[33,2582,2583],{"class":39},"\u002F\u002F logs \"computing...\", returns 84\n",[33,2585,2586,2588,2590,2592,2594],{"class":35,"line":914},[33,2587,2573],{"class":75},[33,2589,80],{"class":79},[33,2591,2578],{"class":99},[33,2593,164],{"class":79},[33,2595,2596],{"class":39},"\u002F\u002F returns 84 (cached, no log)\n",[33,2598,2599],{"class":35,"line":919},[33,2600,59],{"emptyLinePlaceholder":58},[33,2602,2603],{"class":35,"line":924},[33,2604,2605],{"class":39},"\u002F\u002F ── Lazy range generator (compute on demand, not upfront) ──\n",[33,2607,2608,2611,2614,2616,2619,2621,2624,2626,2629,2631,2634],{"class":35,"line":930},[33,2609,2610],{"class":71},"function*",[33,2612,2613],{"class":75}," range",[33,2615,80],{"class":79},[33,2617,2618],{"class":83},"start",[33,2620,87],{"class":79},[33,2622,2623],{"class":83},"end",[33,2625,87],{"class":79},[33,2627,2628],{"class":83},"step",[33,2630,146],{"class":71},[33,2632,2633],{"class":99}," 1",[33,2635,93],{"class":79},[33,2637,2638,2640,2642,2644,2646,2648,2651,2653,2656,2659,2662,2665],{"class":35,"line":940},[33,2639,1108],{"class":71},[33,2641,1111],{"class":79},[33,2643,1114],{"class":71},[33,2645,1117],{"class":79},[33,2647,106],{"class":71},[33,2649,2650],{"class":79}," start; i ",[33,2652,1128],{"class":71},[33,2654,2655],{"class":79}," end; i ",[33,2657,2658],{"class":71},"+=",[33,2660,2661],{"class":79}," step) ",[33,2663,2664],{"class":71},"yield",[33,2666,2667],{"class":79}," i;\n",[33,2669,2670],{"class":35,"line":953},[33,2671,134],{"class":79},[33,2673,2674,2676,2679,2681,2683,2685,2688,2690,2693,2695],{"class":35,"line":970},[33,2675,140],{"class":71},[33,2677,2678],{"class":99}," lazyRange",[33,2680,146],{"class":71},[33,2682,2613],{"class":75},[33,2684,80],{"class":79},[33,2686,2687],{"class":99},"0",[33,2689,87],{"class":79},[33,2691,2692],{"class":99},"1_000_000_000",[33,2694,164],{"class":79},[33,2696,2697],{"class":39},"\u002F\u002F doesn't create a billion items\n",[33,2699,2700,2703,2706,2709],{"class":35,"line":981},[33,2701,2702],{"class":79},"lazyRange.",[33,2704,2705],{"class":75},"next",[33,2707,2708],{"class":79},"().value;  ",[33,2710,2711],{"class":39},"\u002F\u002F 0 (computes on demand)\n",[33,2713,2714],{"class":35,"line":986},[33,2715,2716],{"class":39},"\u002F\u002F Only computes values as they're consumed — O(1) memory, infinite sequences possible.\n",[33,2718,2719],{"class":35,"line":992},[33,2720,59],{"emptyLinePlaceholder":58},[33,2722,2723],{"class":35,"line":1002},[33,2724,2725],{"class":39},"\u002F\u002F ── Virtual list (only render visible items) ──\n",[33,2727,2728,2730,2733,2735,2738,2740,2743,2745,2748,2750,2753],{"class":35,"line":1035},[33,2729,2610],{"class":71},[33,2731,2732],{"class":75}," visibleItems",[33,2734,80],{"class":79},[33,2736,2737],{"class":83},"items",[33,2739,87],{"class":79},[33,2741,2742],{"class":83},"scrollTop",[33,2744,87],{"class":79},[33,2746,2747],{"class":83},"viewportHeight",[33,2749,87],{"class":79},[33,2751,2752],{"class":83},"itemHeight",[33,2754,93],{"class":79},[33,2756,2757,2759,2761,2763,2765,2768,2771,2773],{"class":35,"line":1053},[33,2758,547],{"class":71},[33,2760,1155],{"class":99},[33,2762,146],{"class":71},[33,2764,1594],{"class":79},[33,2766,2767],{"class":75},"floor",[33,2769,2770],{"class":79},"(scrollTop ",[33,2772,1226],{"class":71},[33,2774,2775],{"class":79}," itemHeight);\n",[33,2777,2779,2781,2784,2786,2788,2791,2794,2797,2799,2802,2805,2807,2810,2812],{"class":35,"line":2778},48,[33,2780,547],{"class":71},[33,2782,2783],{"class":99}," end",[33,2785,146],{"class":71},[33,2787,1594],{"class":79},[33,2789,2790],{"class":75},"min",[33,2792,2793],{"class":79},"(start ",[33,2795,2796],{"class":71},"+",[33,2798,1594],{"class":79},[33,2800,2801],{"class":75},"ceil",[33,2803,2804],{"class":79},"(viewportHeight ",[33,2806,1226],{"class":71},[33,2808,2809],{"class":79}," itemHeight), items.",[33,2811,593],{"class":99},[33,2813,374],{"class":79},[33,2815,2817,2819,2821,2823,2825,2827,2829,2831,2834,2836,2838,2840],{"class":35,"line":2816},49,[33,2818,1108],{"class":71},[33,2820,1111],{"class":79},[33,2822,1114],{"class":71},[33,2824,1117],{"class":79},[33,2826,106],{"class":71},[33,2828,2650],{"class":79},[33,2830,1128],{"class":71},[33,2832,2833],{"class":79}," end; i",[33,2835,1137],{"class":71},[33,2837,1140],{"class":79},[33,2839,2664],{"class":71},[33,2841,2842],{"class":79}," { index: i, item: items[i] };\n",[33,2844,2846],{"class":35,"line":2845},50,[33,2847,134],{"class":79},[15,2849,2851],{"id":2850},"tips-tricks","💡 Tips & Tricks",[20,2853,2854],{"language":22},[24,2855,2857],{"className":26,"code":2856,"language":22,"meta":28,"style":28},"\u002F\u002F ── Avoid creating objects in hot paths (hidden class transitions + GC pressure) ──\n\u002F\u002F ❌ Creates a new object each call (GC pressure)\nfunction getCoords() { return { x: Math.random(), y: Math.random() }; }\n\u002F\u002F ✅ Reuse a pre-allocated object (avoid allocation in hot paths)\nconst coords = { x: 0, y: 0 };\nfunction getCoordsFast() { coords.x = Math.random(); coords.y = Math.random(); return coords; }\n\n\u002F\u002F ── Use typed arrays for numeric data (contiguous memory, no boxing) ──\nconst floats = new Float64Array(1000);  \u002F\u002F 8KB, contiguous, cache-friendly\n\u002F\u002F vs: const floats = new Array(1000).fill(0);  \u002F\u002F each element is a boxed number (slower)\n\n\u002F\u002F ── Avoid `arguments` (use rest params — V8 optimizes rest better) ──\n\u002F\u002F ❌ function f() { return Array.from(arguments); }\n\u002F\u002F ✅ function f(...args) { return args; }\n\n\u002F\u002F ── Avoid `delete` (causes hidden class transition → slow) ──\n\u002F\u002F ❌ delete obj.prop;  (transition + deoptimization)\n\u002F\u002F ✅ obj.prop = undefined;  (keep the hidden class, just null the value)\n\n\u002F\u002F ── Use `Object.create(null)` for hash maps (no prototype overhead) ──\nconst map = Object.create(null);  \u002F\u002F no inherited properties (toString, hasOwnProperty, etc.)\nmap.key = \"value\";  \u002F\u002F slightly faster than {} (no prototype chain lookup)\n\n\u002F\u002F ── Batch DOM reads\u002Fwrites (avoid layout thrashing) ──\n\u002F\u002F Read all layout values first, then write all styles (minimize reflows).\n",[30,2858,2859,2864,2869,2895,2900,2921,2953,2957,2962,2985,2993,2997,3002,3007,3012,3016,3021,3026,3031,3035,3040,3062,3077,3081,3086],{"__ignoreMap":28},[33,2860,2861],{"class":35,"line":36},[33,2862,2863],{"class":39},"\u002F\u002F ── Avoid creating objects in hot paths (hidden class transitions + GC pressure) ──\n",[33,2865,2866],{"class":35,"line":43},[33,2867,2868],{"class":39},"\u002F\u002F ❌ Creates a new object each call (GC pressure)\n",[33,2870,2871,2873,2876,2879,2881,2884,2887,2890,2892],{"class":35,"line":49},[33,2872,72],{"class":71},[33,2874,2875],{"class":75}," getCoords",[33,2877,2878],{"class":79},"() { ",[33,2880,426],{"class":71},[33,2882,2883],{"class":79}," { x: Math.",[33,2885,2886],{"class":75},"random",[33,2888,2889],{"class":79},"(), y: Math.",[33,2891,2886],{"class":75},[33,2893,2894],{"class":79},"() }; }\n",[33,2896,2897],{"class":35,"line":55},[33,2898,2899],{"class":39},"\u002F\u002F ✅ Reuse a pre-allocated object (avoid allocation in hot paths)\n",[33,2901,2902,2904,2907,2909,2912,2914,2917,2919],{"class":35,"line":62},[33,2903,140],{"class":71},[33,2905,2906],{"class":99}," coords",[33,2908,146],{"class":71},[33,2910,2911],{"class":79}," { x: ",[33,2913,2687],{"class":99},[33,2915,2916],{"class":79},", y: ",[33,2918,2687],{"class":99},[33,2920,762],{"class":79},[33,2922,2923,2925,2928,2931,2933,2935,2937,2940,2942,2944,2946,2948,2950],{"class":35,"line":68},[33,2924,72],{"class":71},[33,2926,2927],{"class":75}," getCoordsFast",[33,2929,2930],{"class":79},"() { coords.x ",[33,2932,106],{"class":71},[33,2934,1594],{"class":79},[33,2936,2886],{"class":75},[33,2938,2939],{"class":79},"(); coords.y ",[33,2941,106],{"class":71},[33,2943,1594],{"class":79},[33,2945,2886],{"class":75},[33,2947,1423],{"class":79},[33,2949,426],{"class":71},[33,2951,2952],{"class":79}," coords; }\n",[33,2954,2955],{"class":35,"line":96},[33,2956,59],{"emptyLinePlaceholder":58},[33,2958,2959],{"class":35,"line":115},[33,2960,2961],{"class":39},"\u002F\u002F ── Use typed arrays for numeric data (contiguous memory, no boxing) ──\n",[33,2963,2964,2966,2969,2971,2973,2976,2978,2980,2982],{"class":35,"line":131},[33,2965,140],{"class":71},[33,2967,2968],{"class":99}," floats",[33,2970,146],{"class":71},[33,2972,149],{"class":71},[33,2974,2975],{"class":75}," Float64Array",[33,2977,80],{"class":79},[33,2979,976],{"class":99},[33,2981,164],{"class":79},[33,2983,2984],{"class":39},"\u002F\u002F 8KB, contiguous, cache-friendly\n",[33,2986,2987,2990],{"class":35,"line":137},[33,2988,2989],{"class":39},"\u002F\u002F vs: const floats = new Array(1000).fill(0);",[33,2991,2992],{"class":39},"  \u002F\u002F each element is a boxed number (slower)\n",[33,2994,2995],{"class":35,"line":170},[33,2996,59],{"emptyLinePlaceholder":58},[33,2998,2999],{"class":35,"line":199},[33,3000,3001],{"class":39},"\u002F\u002F ── Avoid `arguments` (use rest params — V8 optimizes rest better) ──\n",[33,3003,3004],{"class":35,"line":204},[33,3005,3006],{"class":39},"\u002F\u002F ❌ function f() { return Array.from(arguments); }\n",[33,3008,3009],{"class":35,"line":210},[33,3010,3011],{"class":39},"\u002F\u002F ✅ function f(...args) { return args; }\n",[33,3013,3014],{"class":35,"line":248},[33,3015,59],{"emptyLinePlaceholder":58},[33,3017,3018],{"class":35,"line":287},[33,3019,3020],{"class":39},"\u002F\u002F ── Avoid `delete` (causes hidden class transition → slow) ──\n",[33,3022,3023],{"class":35,"line":314},[33,3024,3025],{"class":39},"\u002F\u002F ❌ delete obj.prop;  (transition + deoptimization)\n",[33,3027,3028],{"class":35,"line":341},[33,3029,3030],{"class":39},"\u002F\u002F ✅ obj.prop = undefined;  (keep the hidden class, just null the value)\n",[33,3032,3033],{"class":35,"line":346},[33,3034,59],{"emptyLinePlaceholder":58},[33,3036,3037],{"class":35,"line":352},[33,3038,3039],{"class":39},"\u002F\u002F ── Use `Object.create(null)` for hash maps (no prototype overhead) ──\n",[33,3041,3042,3044,3047,3049,3051,3053,3055,3057,3059],{"class":35,"line":377},[33,3043,140],{"class":71},[33,3045,3046],{"class":99}," map",[33,3048,146],{"class":71},[33,3050,2053],{"class":79},[33,3052,2056],{"class":75},[33,3054,80],{"class":79},[33,3056,1648],{"class":99},[33,3058,164],{"class":79},[33,3060,3061],{"class":39},"\u002F\u002F no inherited properties (toString, hasOwnProperty, etc.)\n",[33,3063,3064,3067,3069,3072,3074],{"class":35,"line":394},[33,3065,3066],{"class":79},"map.key ",[33,3068,106],{"class":71},[33,3070,3071],{"class":573}," \"value\"",[33,3073,388],{"class":79},[33,3075,3076],{"class":39},"\u002F\u002F slightly faster than {} (no prototype chain lookup)\n",[33,3078,3079],{"class":35,"line":400},[33,3080,59],{"emptyLinePlaceholder":58},[33,3082,3083],{"class":35,"line":405},[33,3084,3085],{"class":39},"\u002F\u002F ── Batch DOM reads\u002Fwrites (avoid layout thrashing) ──\n",[33,3087,3088],{"class":35,"line":411},[33,3089,3090],{"class":39},"\u002F\u002F Read all layout values first, then write all styles (minimize reflows).\n",[15,3092,3094],{"id":3093},"️-edge-cases-gotchas","⚠️ Edge Cases & Gotchas",[20,3096,3097],{"language":22},[24,3098,3100],{"className":26,"code":3099,"language":22,"meta":28,"style":28},"\u002F\u002F ── Microbenchmarking can be misleading (V8 optimizes differently in production) ──\n\u002F\u002F Hot functions in benchmarks get optimized; in production, cold paths might not be.\n\u002F\u002F Use real-world profiling (Chrome DevTools Performance tab) for accurate bottlenecks.\n\n\u002F\u002F ── `delete` on objects causes hidden class transitions (slow) ──\n\u002F\u002F Avoid delete — set to undefined\u002Fnull instead.\n\n\u002F\u002F ── Closure capture keeps large objects alive (memory leak) ──\n\u002F\u002F Extract only what you need from large objects before capturing in closures.\n\n\u002F\u002F ── `Date.now()` is low-resolution (ms) and not monotonic (can go backwards on clock sync) ──\n\u002F\u002F Use `performance.now()` for benchmarking (sub-ms resolution, monotonic).\n\n\u002F\u002F ── JSON.parse(JSON.stringify()) loses types (Date → string, undefined → omitted, NaN → null) ──\n\u002F\u002F Use structuredClone for type-preserving deep clones.\n\n\u002F\u002F ── Adding properties after construction causes hidden class transitions ──\n\u002F\u002F Declare all properties in the constructor for consistent hidden classes.\n",[30,3101,3102,3107,3112,3117,3121,3126,3131,3135,3140,3145,3149,3154,3159,3163,3168,3173,3177,3182],{"__ignoreMap":28},[33,3103,3104],{"class":35,"line":36},[33,3105,3106],{"class":39},"\u002F\u002F ── Microbenchmarking can be misleading (V8 optimizes differently in production) ──\n",[33,3108,3109],{"class":35,"line":43},[33,3110,3111],{"class":39},"\u002F\u002F Hot functions in benchmarks get optimized; in production, cold paths might not be.\n",[33,3113,3114],{"class":35,"line":49},[33,3115,3116],{"class":39},"\u002F\u002F Use real-world profiling (Chrome DevTools Performance tab) for accurate bottlenecks.\n",[33,3118,3119],{"class":35,"line":55},[33,3120,59],{"emptyLinePlaceholder":58},[33,3122,3123],{"class":35,"line":62},[33,3124,3125],{"class":39},"\u002F\u002F ── `delete` on objects causes hidden class transitions (slow) ──\n",[33,3127,3128],{"class":35,"line":68},[33,3129,3130],{"class":39},"\u002F\u002F Avoid delete — set to undefined\u002Fnull instead.\n",[33,3132,3133],{"class":35,"line":96},[33,3134,59],{"emptyLinePlaceholder":58},[33,3136,3137],{"class":35,"line":115},[33,3138,3139],{"class":39},"\u002F\u002F ── Closure capture keeps large objects alive (memory leak) ──\n",[33,3141,3142],{"class":35,"line":131},[33,3143,3144],{"class":39},"\u002F\u002F Extract only what you need from large objects before capturing in closures.\n",[33,3146,3147],{"class":35,"line":137},[33,3148,59],{"emptyLinePlaceholder":58},[33,3150,3151],{"class":35,"line":170},[33,3152,3153],{"class":39},"\u002F\u002F ── `Date.now()` is low-resolution (ms) and not monotonic (can go backwards on clock sync) ──\n",[33,3155,3156],{"class":35,"line":199},[33,3157,3158],{"class":39},"\u002F\u002F Use `performance.now()` for benchmarking (sub-ms resolution, monotonic).\n",[33,3160,3161],{"class":35,"line":204},[33,3162,59],{"emptyLinePlaceholder":58},[33,3164,3165],{"class":35,"line":210},[33,3166,3167],{"class":39},"\u002F\u002F ── JSON.parse(JSON.stringify()) loses types (Date → string, undefined → omitted, NaN → null) ──\n",[33,3169,3170],{"class":35,"line":248},[33,3171,3172],{"class":39},"\u002F\u002F Use structuredClone for type-preserving deep clones.\n",[33,3174,3175],{"class":35,"line":287},[33,3176,59],{"emptyLinePlaceholder":58},[33,3178,3179],{"class":35,"line":314},[33,3180,3181],{"class":39},"\u002F\u002F ── Adding properties after construction causes hidden class transitions ──\n",[33,3183,3184],{"class":35,"line":341},[33,3185,3186],{"class":39},"\u002F\u002F Declare all properties in the constructor for consistent hidden classes.\n",[15,3188,3190],{"id":3189},"quick-quiz","🧠 Quick Quiz",[3192,3193,3194],"p",{},"Why is this code slow for large arrays?",[20,3196,3197],{"language":22},[24,3198,3200],{"className":26,"code":3199,"language":22,"meta":28,"style":28},"function sum(arr) {\n    let total = 0;\n    for (let i = 0; i \u003C arr.length; i++) {\n        total += arr[i];\n    }\n    return total;\n}\nconst bigArray = new Array(10_000_000);\nfor (let i = 0; i \u003C bigArray.length; i++) bigArray[i] = Math.random();\nsum(bigArray);  \u002F\u002F slow\n",[30,3201,3202,3216,3230,3259,3269,3273,3280,3284,3304,3343],{"__ignoreMap":28},[33,3203,3204,3206,3209,3211,3214],{"class":35,"line":36},[33,3205,72],{"class":71},[33,3207,3208],{"class":75}," sum",[33,3210,80],{"class":79},[33,3212,3213],{"class":83},"arr",[33,3215,93],{"class":79},[33,3217,3218,3221,3224,3226,3228],{"class":35,"line":43},[33,3219,3220],{"class":71},"    let",[33,3222,3223],{"class":79}," total ",[33,3225,106],{"class":71},[33,3227,1122],{"class":99},[33,3229,2247],{"class":79},[33,3231,3232,3234,3236,3238,3240,3242,3244,3246,3248,3251,3253,3255,3257],{"class":35,"line":49},[33,3233,1108],{"class":71},[33,3235,1111],{"class":79},[33,3237,1114],{"class":71},[33,3239,1117],{"class":79},[33,3241,106],{"class":71},[33,3243,1122],{"class":99},[33,3245,1125],{"class":79},[33,3247,1128],{"class":71},[33,3249,3250],{"class":79}," arr.",[33,3252,593],{"class":99},[33,3254,1134],{"class":79},[33,3256,1137],{"class":71},[33,3258,93],{"class":79},[33,3260,3261,3264,3266],{"class":35,"line":55},[33,3262,3263],{"class":79},"        total ",[33,3265,2658],{"class":71},[33,3267,3268],{"class":79}," arr[i];\n",[33,3270,3271],{"class":35,"line":62},[33,3272,2116],{"class":79},[33,3274,3275,3277],{"class":35,"line":68},[33,3276,581],{"class":71},[33,3278,3279],{"class":79}," total;\n",[33,3281,3282],{"class":35,"line":96},[33,3283,134],{"class":79},[33,3285,3286,3288,3291,3293,3295,3297,3299,3302],{"class":35,"line":115},[33,3287,140],{"class":71},[33,3289,3290],{"class":99}," bigArray",[33,3292,146],{"class":71},[33,3294,149],{"class":71},[33,3296,557],{"class":75},[33,3298,80],{"class":79},[33,3300,3301],{"class":99},"10_000_000",[33,3303,374],{"class":79},[33,3305,3306,3309,3311,3313,3315,3317,3319,3321,3323,3326,3328,3330,3332,3335,3337,3339,3341],{"class":35,"line":131},[33,3307,3308],{"class":71},"for",[33,3310,1111],{"class":79},[33,3312,1114],{"class":71},[33,3314,1117],{"class":79},[33,3316,106],{"class":71},[33,3318,1122],{"class":99},[33,3320,1125],{"class":79},[33,3322,1128],{"class":71},[33,3324,3325],{"class":79}," bigArray.",[33,3327,593],{"class":99},[33,3329,1134],{"class":79},[33,3331,1137],{"class":71},[33,3333,3334],{"class":79},") bigArray[i] ",[33,3336,106],{"class":71},[33,3338,1594],{"class":79},[33,3340,2886],{"class":75},[33,3342,860],{"class":79},[33,3344,3345,3348,3351],{"class":35,"line":137},[33,3346,3347],{"class":75},"sum",[33,3349,3350],{"class":79},"(bigArray);  ",[33,3352,3353],{"class":39},"\u002F\u002F slow\n",[3355,3356,3357,3361,3373,3408,3414,3460],"details",{},[3358,3359,3360],"summary",{},"Answer",[3192,3362,3363,3364,3367,3368,3372],{},"The array is created with ",[30,3365,3366],{},"new Array(10_000_000)"," — a ",[3369,3370,3371],"strong",{},"sparse array with holes",". The loop fills it with values, but V8 may represent this as a dictionary (slow mode) rather than a packed array (fast mode) because:",[3374,3375,3376,3390,3401],"ol",{},[3377,3378,3379,3382,3383,3385,3386,3389],"li",{},[30,3380,3381],{},"new Array(n)"," creates an array with ",[30,3384,2529],{}," ",[3369,3387,3388],{},"holes"," (empty slots, not packed numbers).",[3377,3391,3392,3393,3396,3397,3400],{},"Filling it with ",[30,3394,3395],{},"Math.random()"," converts each hole to a double-precision number, but V8 may not transition to a packed ",[30,3398,3399],{},"PACKED_DOUBLE_ELEMENTS"," hidden class until it's certain all elements are filled.",[3377,3402,3403,3404,3407],{},"Each ",[30,3405,3406],{},"arr[i]"," access on a hole-containing array is slower (extra checks).",[3192,3409,3410,3413],{},[3369,3411,3412],{},"Fix",": Create a packed array from the start:",[24,3415,3417],{"className":26,"code":3416,"language":22,"meta":28,"style":28},"\u002F\u002F ✅ Packed array (fast — V8 uses PACKED_DOUBLE_ELEMENTS)\nconst bigArray = Array.from({ length: 10_000_000 }, () => Math.random());\n\u002F\u002F or: const bigArray = new Float64Array(10_000_000);  \u002F\u002F typed array (fastest for numbers)\n",[30,3418,3419,3424,3452],{"__ignoreMap":28},[33,3420,3421],{"class":35,"line":36},[33,3422,3423],{"class":39},"\u002F\u002F ✅ Packed array (fast — V8 uses PACKED_DOUBLE_ELEMENTS)\n",[33,3425,3426,3428,3430,3432,3434,3436,3438,3440,3443,3445,3447,3449],{"class":35,"line":43},[33,3427,140],{"class":71},[33,3429,3290],{"class":99},[33,3431,146],{"class":71},[33,3433,2035],{"class":79},[33,3435,2151],{"class":75},[33,3437,2154],{"class":79},[33,3439,3301],{"class":99},[33,3441,3442],{"class":79}," }, () ",[33,3444,587],{"class":71},[33,3446,1594],{"class":79},[33,3448,2886],{"class":75},[33,3450,3451],{"class":79},"());\n",[33,3453,3454,3457],{"class":35,"line":49},[33,3455,3456],{"class":39},"\u002F\u002F or: const bigArray = new Float64Array(10_000_000);",[33,3458,3459],{"class":39},"  \u002F\u002F typed array (fastest for numbers)\n",[3192,3461,3462,3465,3466,3468,3469,3472],{},[3369,3463,3464],{},"The lesson",": ",[30,3467,3381],{}," creates a sparse array with holes. V8 optimizes packed arrays (no holes, consistent element types) much better than sparse arrays. Use ",[30,3470,3471],{},"Array.from()"," or typed arrays for large numeric arrays.",[3474,3475,3476],"style",{},"html pre.shiki code .sdCPZ, html code.shiki .sdCPZ{--shiki-default:#6A737D;--shiki-github-dark:#6A737D}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 .sCrzJ, html code.shiki .sCrzJ{--shiki-default:#E36209;--shiki-github-dark:#FFAB70}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 .sJ6F3, html code.shiki .sJ6F3{--shiki-default:#032F62;--shiki-github-dark:#9ECBFF}",{"title":28,"searchDepth":43,"depth":43,"links":3478},[3479,3480,3481,3483,3485,3486,3487,3488],{"id":17,"depth":43,"text":18},{"id":510,"depth":43,"text":511},{"id":1058,"depth":43,"text":3482},"Benchmarking with performance.now",{"id":1712,"depth":43,"text":3484},"Deep Clone Performance: structuredClone vs JSON",{"id":2203,"depth":43,"text":2204},{"id":2850,"depth":43,"text":2851},{"id":3093,"depth":43,"text":3094},{"id":3189,"depth":43,"text":3190},"Deep-dive into JavaScript performance: V8 hidden classes and inline caches, closure-induced memory leaks, structuredClone vs JSON, benchmarking with performance.now, and lazy evaluation patterns. Code-first reference for senior engineers.","md",{},"\u002Fjs\u002F26-performance-and-optimization",{"title":5,"description":3489},"js\u002F26-performance-and-optimization","wbVwfSxFBPl482Jz2j0oISf04myGvygM9IvALX6VFoU",1789924649549]