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