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