[{"data":1,"prerenderedAt":3155},["ShallowReactive",2],{"page-\u002Fjs\u002F07-objects-and-properties":3},{"id":4,"title":5,"body":6,"description":3148,"extension":3149,"meta":3150,"navigation":58,"path":3151,"seo":3152,"stem":3153,"__hash__":3154},"content\u002Fjs\u002F07-objects-and-properties.md","JavaScript 07 — Object Internals: Property Descriptors, Prototypes & Immutability",{"type":7,"value":8,"toc":3138},"minimark",[9,14,19,689,693,972,976,1352,1356,1658,1662,2222,2226,2601,2605,2974,2978,2989,3039,3134],[10,11,13],"h1",{"id":12},"_07-object-internals-property-descriptors-prototypes-immutability","07 — Object Internals: Property Descriptors, Prototypes & Immutability",[15,16,18],"h2",{"id":17},"property-descriptors-the-full-control-surface","Property Descriptors: The Full Control Surface",[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 ── Every property has a descriptor with 6 attributes ──\n\u002F\u002F Data descriptor: { value, writable, enumerable, configurable }\n\u002F\u002F Accessor descriptor: { get, set, enumerable, configurable }\n\n\u002F\u002F ── Default descriptor values (when creating via =) ──\nconst obj = {};\nobj.x = 1;\nconsole.log(Object.getOwnPropertyDescriptor(obj, \"x\"));\n\u002F\u002F { value: 1, writable: true, enumerable: true, configurable: true }\n\u002F\u002F ┚ All default to true when assigned via `=` or object literal.\n\n\u002F\u002F ── Object.defineProperty: explicit descriptor (defaults are FALSE) ──\nObject.defineProperty(obj, \"y\", {\n    value: 2,\n    \u002F\u002F writable: false,    ← defaults to false (immutable)\n    \u002F\u002F enumerable: false,  ← defaults to false (hidden from for...in)\n    \u002F\u002F configurable: false ← defaults to false (can't delete or redefine)\n});\nconsole.log(Object.getOwnPropertyDescriptor(obj, \"y\"));\n\u002F\u002F { value: 2, writable: false, enumerable: false, configurable: false }\n\u002F\u002F ⚠️ The default for defineProperty is FALSE (opposite of `=` assignment!)\n\n\u002F\u002F ── writable: false prevents reassignment (silently in sloppy, throws in strict) ──\n\"use strict\";\nconst obj2 = {};\nObject.defineProperty(obj2, \"x\", { value: 1, writable: false });\n\u002F\u002F obj2.x = 2;  \u002F\u002F TypeError: Cannot assign to read only property 'x'\n\u002F\u002F In sloppy mode: fails silently (no error, value unchanged)\n\n\u002F\u002F ── enumerable: false hides from for...in and Object.keys ──\nconst obj3 = { a: 1 };\nObject.defineProperty(obj3, \"b\", { value: 2, enumerable: false });\nfor (const key in obj3) console.log(key);  \u002F\u002F \"a\" only (b is hidden)\nconsole.log(Object.keys(obj3));  \u002F\u002F [\"a\"] (b not enumerable)\nconsole.log(Object.getOwnPropertyNames(obj3));  \u002F\u002F [\"a\", \"b\"] (includes non-enumerable)\nconsole.log(Reflect.ownKeys(obj3));  \u002F\u002F [\"a\", \"b\"] (includes symbols + non-enumerable)\n\n\u002F\u002F ── configurable: false prevents deletion and descriptor changes ──\nconst obj4 = {};\nObject.defineProperty(obj4, \"x\", { value: 1, configurable: false });\n\u002F\u002F delete obj4.x;  \u002F\u002F TypeError: Cannot delete property (in strict mode)\n\u002F\u002F Object.defineProperty(obj4, \"x\", { value: 2 });  \u002F\u002F TypeError (can't redefine)\n\u002F\u002F EXCEPTION: writable can be changed from true → false (but not back) even if configurable: false\n\n\u002F\u002F ── Accessor properties (getters\u002Fsetters) ──\nconst obj5 = {};\nlet _private = 0;\nObject.defineProperty(obj5, \"value\", {\n    get() { return _private; },\n    set(v) { if (v \u003C 0) throw new Error(\"negative\"); _private = v; },\n    enumerable: true,\n    configurable: true,\n});\nobj5.value = 10;\nconsole.log(obj5.value);  \u002F\u002F 10\n\u002F\u002F obj5.value = -1;  \u002F\u002F throws (setter validates)\n","",[30,31,32,41,47,53,60,66,84,99,125,131,137,142,148,165,177,183,189,195,201,218,224,230,235,241,249,261,288,297,303,308,314,332,356,384,402,419,437,442,448,460,483,492,501,507,512,518,530,546,561,576,628,639,649,654,667,680],"code",{"__ignoreMap":28},[33,34,37],"span",{"class":35,"line":36},"line",1,[33,38,40],{"class":39},"sdCPZ","\u002F\u002F ── Every property has a descriptor with 6 attributes ──\n",[33,42,44],{"class":35,"line":43},2,[33,45,46],{"class":39},"\u002F\u002F Data descriptor: { value, writable, enumerable, configurable }\n",[33,48,50],{"class":35,"line":49},3,[33,51,52],{"class":39},"\u002F\u002F Accessor descriptor: { get, set, enumerable, configurable }\n",[33,54,56],{"class":35,"line":55},4,[33,57,59],{"emptyLinePlaceholder":58},true,"\n",[33,61,63],{"class":35,"line":62},5,[33,64,65],{"class":39},"\u002F\u002F ── Default descriptor values (when creating via =) ──\n",[33,67,69,73,77,80],{"class":35,"line":68},6,[33,70,72],{"class":71},"svdQ7","const",[33,74,76],{"class":75},"snvgF"," obj",[33,78,79],{"class":71}," =",[33,81,83],{"class":82},"ssxIu"," {};\n",[33,85,87,90,93,96],{"class":35,"line":86},7,[33,88,89],{"class":82},"obj.x ",[33,91,92],{"class":71},"=",[33,94,95],{"class":75}," 1",[33,97,98],{"class":82},";\n",[33,100,102,105,109,112,115,118,122],{"class":35,"line":101},8,[33,103,104],{"class":82},"console.",[33,106,108],{"class":107},"sIsaT","log",[33,110,111],{"class":82},"(Object.",[33,113,114],{"class":107},"getOwnPropertyDescriptor",[33,116,117],{"class":82},"(obj, ",[33,119,121],{"class":120},"sJ6F3","\"x\"",[33,123,124],{"class":82},"));\n",[33,126,128],{"class":35,"line":127},9,[33,129,130],{"class":39},"\u002F\u002F { value: 1, writable: true, enumerable: true, configurable: true }\n",[33,132,134],{"class":35,"line":133},10,[33,135,136],{"class":39},"\u002F\u002F ┚ All default to true when assigned via `=` or object literal.\n",[33,138,140],{"class":35,"line":139},11,[33,141,59],{"emptyLinePlaceholder":58},[33,143,145],{"class":35,"line":144},12,[33,146,147],{"class":39},"\u002F\u002F ── Object.defineProperty: explicit descriptor (defaults are FALSE) ──\n",[33,149,151,154,157,159,162],{"class":35,"line":150},13,[33,152,153],{"class":82},"Object.",[33,155,156],{"class":107},"defineProperty",[33,158,117],{"class":82},[33,160,161],{"class":120},"\"y\"",[33,163,164],{"class":82},", {\n",[33,166,168,171,174],{"class":35,"line":167},14,[33,169,170],{"class":82},"    value: ",[33,172,173],{"class":75},"2",[33,175,176],{"class":82},",\n",[33,178,180],{"class":35,"line":179},15,[33,181,182],{"class":39},"    \u002F\u002F writable: false,    ← defaults to false (immutable)\n",[33,184,186],{"class":35,"line":185},16,[33,187,188],{"class":39},"    \u002F\u002F enumerable: false,  ← defaults to false (hidden from for...in)\n",[33,190,192],{"class":35,"line":191},17,[33,193,194],{"class":39},"    \u002F\u002F configurable: false ← defaults to false (can't delete or redefine)\n",[33,196,198],{"class":35,"line":197},18,[33,199,200],{"class":82},"});\n",[33,202,204,206,208,210,212,214,216],{"class":35,"line":203},19,[33,205,104],{"class":82},[33,207,108],{"class":107},[33,209,111],{"class":82},[33,211,114],{"class":107},[33,213,117],{"class":82},[33,215,161],{"class":120},[33,217,124],{"class":82},[33,219,221],{"class":35,"line":220},20,[33,222,223],{"class":39},"\u002F\u002F { value: 2, writable: false, enumerable: false, configurable: false }\n",[33,225,227],{"class":35,"line":226},21,[33,228,229],{"class":39},"\u002F\u002F ⚠️ The default for defineProperty is FALSE (opposite of `=` assignment!)\n",[33,231,233],{"class":35,"line":232},22,[33,234,59],{"emptyLinePlaceholder":58},[33,236,238],{"class":35,"line":237},23,[33,239,240],{"class":39},"\u002F\u002F ── writable: false prevents reassignment (silently in sloppy, throws in strict) ──\n",[33,242,244,247],{"class":35,"line":243},24,[33,245,246],{"class":120},"\"use strict\"",[33,248,98],{"class":82},[33,250,252,254,257,259],{"class":35,"line":251},25,[33,253,72],{"class":71},[33,255,256],{"class":75}," obj2",[33,258,79],{"class":71},[33,260,83],{"class":82},[33,262,264,266,268,271,273,276,279,282,285],{"class":35,"line":263},26,[33,265,153],{"class":82},[33,267,156],{"class":107},[33,269,270],{"class":82},"(obj2, ",[33,272,121],{"class":120},[33,274,275],{"class":82},", { value: ",[33,277,278],{"class":75},"1",[33,280,281],{"class":82},", writable: ",[33,283,284],{"class":75},"false",[33,286,287],{"class":82}," });\n",[33,289,291,294],{"class":35,"line":290},27,[33,292,293],{"class":39},"\u002F\u002F obj2.x = 2;",[33,295,296],{"class":39},"  \u002F\u002F TypeError: Cannot assign to read only property 'x'\n",[33,298,300],{"class":35,"line":299},28,[33,301,302],{"class":39},"\u002F\u002F In sloppy mode: fails silently (no error, value unchanged)\n",[33,304,306],{"class":35,"line":305},29,[33,307,59],{"emptyLinePlaceholder":58},[33,309,311],{"class":35,"line":310},30,[33,312,313],{"class":39},"\u002F\u002F ── enumerable: false hides from for...in and Object.keys ──\n",[33,315,317,319,322,324,327,329],{"class":35,"line":316},31,[33,318,72],{"class":71},[33,320,321],{"class":75}," obj3",[33,323,79],{"class":71},[33,325,326],{"class":82}," { a: ",[33,328,278],{"class":75},[33,330,331],{"class":82}," };\n",[33,333,335,337,339,342,345,347,349,352,354],{"class":35,"line":334},32,[33,336,153],{"class":82},[33,338,156],{"class":107},[33,340,341],{"class":82},"(obj3, ",[33,343,344],{"class":120},"\"b\"",[33,346,275],{"class":82},[33,348,173],{"class":75},[33,350,351],{"class":82},", enumerable: ",[33,353,284],{"class":75},[33,355,287],{"class":82},[33,357,359,362,365,367,370,373,376,378,381],{"class":35,"line":358},33,[33,360,361],{"class":71},"for",[33,363,364],{"class":82}," (",[33,366,72],{"class":71},[33,368,369],{"class":75}," key",[33,371,372],{"class":71}," in",[33,374,375],{"class":82}," obj3) console.",[33,377,108],{"class":107},[33,379,380],{"class":82},"(key);  ",[33,382,383],{"class":39},"\u002F\u002F \"a\" only (b is hidden)\n",[33,385,387,389,391,393,396,399],{"class":35,"line":386},34,[33,388,104],{"class":82},[33,390,108],{"class":107},[33,392,111],{"class":82},[33,394,395],{"class":107},"keys",[33,397,398],{"class":82},"(obj3));  ",[33,400,401],{"class":39},"\u002F\u002F [\"a\"] (b not enumerable)\n",[33,403,405,407,409,411,414,416],{"class":35,"line":404},35,[33,406,104],{"class":82},[33,408,108],{"class":107},[33,410,111],{"class":82},[33,412,413],{"class":107},"getOwnPropertyNames",[33,415,398],{"class":82},[33,417,418],{"class":39},"\u002F\u002F [\"a\", \"b\"] (includes non-enumerable)\n",[33,420,422,424,426,429,432,434],{"class":35,"line":421},36,[33,423,104],{"class":82},[33,425,108],{"class":107},[33,427,428],{"class":82},"(Reflect.",[33,430,431],{"class":107},"ownKeys",[33,433,398],{"class":82},[33,435,436],{"class":39},"\u002F\u002F [\"a\", \"b\"] (includes symbols + non-enumerable)\n",[33,438,440],{"class":35,"line":439},37,[33,441,59],{"emptyLinePlaceholder":58},[33,443,445],{"class":35,"line":444},38,[33,446,447],{"class":39},"\u002F\u002F ── configurable: false prevents deletion and descriptor changes ──\n",[33,449,451,453,456,458],{"class":35,"line":450},39,[33,452,72],{"class":71},[33,454,455],{"class":75}," obj4",[33,457,79],{"class":71},[33,459,83],{"class":82},[33,461,463,465,467,470,472,474,476,479,481],{"class":35,"line":462},40,[33,464,153],{"class":82},[33,466,156],{"class":107},[33,468,469],{"class":82},"(obj4, ",[33,471,121],{"class":120},[33,473,275],{"class":82},[33,475,278],{"class":75},[33,477,478],{"class":82},", configurable: ",[33,480,284],{"class":75},[33,482,287],{"class":82},[33,484,486,489],{"class":35,"line":485},41,[33,487,488],{"class":39},"\u002F\u002F delete obj4.x;",[33,490,491],{"class":39},"  \u002F\u002F TypeError: Cannot delete property (in strict mode)\n",[33,493,495,498],{"class":35,"line":494},42,[33,496,497],{"class":39},"\u002F\u002F Object.defineProperty(obj4, \"x\", { value: 2 });",[33,499,500],{"class":39},"  \u002F\u002F TypeError (can't redefine)\n",[33,502,504],{"class":35,"line":503},43,[33,505,506],{"class":39},"\u002F\u002F EXCEPTION: writable can be changed from true → false (but not back) even if configurable: false\n",[33,508,510],{"class":35,"line":509},44,[33,511,59],{"emptyLinePlaceholder":58},[33,513,515],{"class":35,"line":514},45,[33,516,517],{"class":39},"\u002F\u002F ── Accessor properties (getters\u002Fsetters) ──\n",[33,519,521,523,526,528],{"class":35,"line":520},46,[33,522,72],{"class":71},[33,524,525],{"class":75}," obj5",[33,527,79],{"class":71},[33,529,83],{"class":82},[33,531,533,536,539,541,544],{"class":35,"line":532},47,[33,534,535],{"class":71},"let",[33,537,538],{"class":82}," _private ",[33,540,92],{"class":71},[33,542,543],{"class":75}," 0",[33,545,98],{"class":82},[33,547,549,551,553,556,559],{"class":35,"line":548},48,[33,550,153],{"class":82},[33,552,156],{"class":107},[33,554,555],{"class":82},"(obj5, ",[33,557,558],{"class":120},"\"value\"",[33,560,164],{"class":82},[33,562,564,567,570,573],{"class":35,"line":563},49,[33,565,566],{"class":107},"    get",[33,568,569],{"class":82},"() { ",[33,571,572],{"class":71},"return",[33,574,575],{"class":82}," _private; },\n",[33,577,579,582,585,589,592,595,598,601,603,606,609,612,615,617,620,623,625],{"class":35,"line":578},50,[33,580,581],{"class":107},"    set",[33,583,584],{"class":82},"(",[33,586,588],{"class":587},"sCrzJ","v",[33,590,591],{"class":82},") { ",[33,593,594],{"class":71},"if",[33,596,597],{"class":82}," (v ",[33,599,600],{"class":71},"\u003C",[33,602,543],{"class":75},[33,604,605],{"class":82},") ",[33,607,608],{"class":71},"throw",[33,610,611],{"class":71}," new",[33,613,614],{"class":107}," Error",[33,616,584],{"class":82},[33,618,619],{"class":120},"\"negative\"",[33,621,622],{"class":82},"); _private ",[33,624,92],{"class":71},[33,626,627],{"class":82}," v; },\n",[33,629,631,634,637],{"class":35,"line":630},51,[33,632,633],{"class":82},"    enumerable: ",[33,635,636],{"class":75},"true",[33,638,176],{"class":82},[33,640,642,645,647],{"class":35,"line":641},52,[33,643,644],{"class":82},"    configurable: ",[33,646,636],{"class":75},[33,648,176],{"class":82},[33,650,652],{"class":35,"line":651},53,[33,653,200],{"class":82},[33,655,657,660,662,665],{"class":35,"line":656},54,[33,658,659],{"class":82},"obj5.value ",[33,661,92],{"class":71},[33,663,664],{"class":75}," 10",[33,666,98],{"class":82},[33,668,670,672,674,677],{"class":35,"line":669},55,[33,671,104],{"class":82},[33,673,108],{"class":107},[33,675,676],{"class":82},"(obj5.value);  ",[33,678,679],{"class":39},"\u002F\u002F 10\n",[33,681,683,686],{"class":35,"line":682},56,[33,684,685],{"class":39},"\u002F\u002F obj5.value = -1;",[33,687,688],{"class":39},"  \u002F\u002F throws (setter validates)\n",[15,690,692],{"id":691},"anti-pattern-shallow-freeze-doesnt-prevent-nested-mutation","Anti-Pattern: Shallow Freeze Doesn't Prevent Nested Mutation",[20,694,695],{"language":22},[24,696,698],{"className":26,"code":697,"language":22,"meta":28,"style":28},"\u002F\u002F ❌ NAIVE — Object.freeze is shallow (only freezes the top level)\nconst config = Object.freeze({\n    server: { host: \"localhost\", port: 3000 },\n});\nconfig.server.port = 9999;  \u002F\u002F ✓ works! (server is NOT frozen — only the top object is)\nconsole.log(config.server.port);  \u002F\u002F 9999 — mutated despite the freeze\n\u002F\u002F Object.freeze prevents reassignment of top-level properties and top-level mutation,\n\u002F\u002F but nested objects are still mutable.\n\n\u002F\u002F ✅ CORRECT — deep freeze (recursively freeze all nested objects)\nfunction deepFreeze(obj) {\n    \u002F\u002F Get all property names (including non-enumerable)\n    const propNames = Object.getOwnPropertyNames(obj);\n    \u002F\u002F Freeze each nested object first (depth-first)\n    for (const name of propNames) {\n        const value = obj[name];\n        if (value && typeof value === \"object\") {\n            deepFreeze(value);  \u002F\u002F recurse\n        }\n    }\n    return Object.freeze(obj);  \u002F\u002F freeze the top level last\n}\n\nconst config2 = deepFreeze({\n    server: { host: \"localhost\", port: 3000 },\n});\n\u002F\u002F config2.server.port = 9999;  \u002F\u002F TypeError: Cannot assign (frozen at all levels)\n",[30,699,700,705,723,740,744,760,772,777,782,786,791,807,812,829,834,852,865,890,901,906,911,926,931,935,948,960,964],{"__ignoreMap":28},[33,701,702],{"class":35,"line":36},[33,703,704],{"class":39},"\u002F\u002F ❌ NAIVE — Object.freeze is shallow (only freezes the top level)\n",[33,706,707,709,712,714,717,720],{"class":35,"line":43},[33,708,72],{"class":71},[33,710,711],{"class":75}," config",[33,713,79],{"class":71},[33,715,716],{"class":82}," Object.",[33,718,719],{"class":107},"freeze",[33,721,722],{"class":82},"({\n",[33,724,725,728,731,734,737],{"class":35,"line":49},[33,726,727],{"class":82},"    server: { host: ",[33,729,730],{"class":120},"\"localhost\"",[33,732,733],{"class":82},", port: ",[33,735,736],{"class":75},"3000",[33,738,739],{"class":82}," },\n",[33,741,742],{"class":35,"line":55},[33,743,200],{"class":82},[33,745,746,749,751,754,757],{"class":35,"line":62},[33,747,748],{"class":82},"config.server.port ",[33,750,92],{"class":71},[33,752,753],{"class":75}," 9999",[33,755,756],{"class":82},";  ",[33,758,759],{"class":39},"\u002F\u002F ✓ works! (server is NOT frozen — only the top object is)\n",[33,761,762,764,766,769],{"class":35,"line":68},[33,763,104],{"class":82},[33,765,108],{"class":107},[33,767,768],{"class":82},"(config.server.port);  ",[33,770,771],{"class":39},"\u002F\u002F 9999 — mutated despite the freeze\n",[33,773,774],{"class":35,"line":86},[33,775,776],{"class":39},"\u002F\u002F Object.freeze prevents reassignment of top-level properties and top-level mutation,\n",[33,778,779],{"class":35,"line":101},[33,780,781],{"class":39},"\u002F\u002F but nested objects are still mutable.\n",[33,783,784],{"class":35,"line":127},[33,785,59],{"emptyLinePlaceholder":58},[33,787,788],{"class":35,"line":133},[33,789,790],{"class":39},"\u002F\u002F ✅ CORRECT — deep freeze (recursively freeze all nested objects)\n",[33,792,793,796,799,801,804],{"class":35,"line":139},[33,794,795],{"class":71},"function",[33,797,798],{"class":107}," deepFreeze",[33,800,584],{"class":82},[33,802,803],{"class":587},"obj",[33,805,806],{"class":82},") {\n",[33,808,809],{"class":35,"line":144},[33,810,811],{"class":39},"    \u002F\u002F Get all property names (including non-enumerable)\n",[33,813,814,817,820,822,824,826],{"class":35,"line":150},[33,815,816],{"class":71},"    const",[33,818,819],{"class":75}," propNames",[33,821,79],{"class":71},[33,823,716],{"class":82},[33,825,413],{"class":107},[33,827,828],{"class":82},"(obj);\n",[33,830,831],{"class":35,"line":167},[33,832,833],{"class":39},"    \u002F\u002F Freeze each nested object first (depth-first)\n",[33,835,836,839,841,843,846,849],{"class":35,"line":179},[33,837,838],{"class":71},"    for",[33,840,364],{"class":82},[33,842,72],{"class":71},[33,844,845],{"class":75}," name",[33,847,848],{"class":71}," of",[33,850,851],{"class":82}," propNames) {\n",[33,853,854,857,860,862],{"class":35,"line":185},[33,855,856],{"class":71},"        const",[33,858,859],{"class":75}," value",[33,861,79],{"class":71},[33,863,864],{"class":82}," obj[name];\n",[33,866,867,870,873,876,879,882,885,888],{"class":35,"line":191},[33,868,869],{"class":71},"        if",[33,871,872],{"class":82}," (value ",[33,874,875],{"class":71},"&&",[33,877,878],{"class":71}," typeof",[33,880,881],{"class":82}," value ",[33,883,884],{"class":71},"===",[33,886,887],{"class":120}," \"object\"",[33,889,806],{"class":82},[33,891,892,895,898],{"class":35,"line":197},[33,893,894],{"class":107},"            deepFreeze",[33,896,897],{"class":82},"(value);  ",[33,899,900],{"class":39},"\u002F\u002F recurse\n",[33,902,903],{"class":35,"line":203},[33,904,905],{"class":82},"        }\n",[33,907,908],{"class":35,"line":220},[33,909,910],{"class":82},"    }\n",[33,912,913,916,918,920,923],{"class":35,"line":226},[33,914,915],{"class":71},"    return",[33,917,716],{"class":82},[33,919,719],{"class":107},[33,921,922],{"class":82},"(obj);  ",[33,924,925],{"class":39},"\u002F\u002F freeze the top level last\n",[33,927,928],{"class":35,"line":232},[33,929,930],{"class":82},"}\n",[33,932,933],{"class":35,"line":237},[33,934,59],{"emptyLinePlaceholder":58},[33,936,937,939,942,944,946],{"class":35,"line":243},[33,938,72],{"class":71},[33,940,941],{"class":75}," config2",[33,943,79],{"class":71},[33,945,798],{"class":107},[33,947,722],{"class":82},[33,949,950,952,954,956,958],{"class":35,"line":251},[33,951,727],{"class":82},[33,953,730],{"class":120},[33,955,733],{"class":82},[33,957,736],{"class":75},[33,959,739],{"class":82},[33,961,962],{"class":35,"line":263},[33,963,200],{"class":82},[33,965,966,969],{"class":35,"line":290},[33,967,968],{"class":39},"\u002F\u002F config2.server.port = 9999;",[33,970,971],{"class":39},"  \u002F\u002F TypeError: Cannot assign (frozen at all levels)\n",[15,973,975],{"id":974},"the-prototype-chain","The Prototype Chain",[20,977,978],{"language":22},[24,979,981],{"className":26,"code":980,"language":22,"meta":28,"style":28},"\u002F\u002F ── Every object has an internal [[Prototype]] link (accessible via __proto__ or Object.getPrototypeOf) ──\n\u002F\u002F Property lookup follows the prototype chain until found or null is reached.\n\nconst animal = { breathe() { return \"breathing\"; } };\nconst dog = Object.create(animal);  \u002F\u002F dog.__proto__ = animal\ndog.bark = function() { return \"woof\"; };\n\nconsole.log(dog.bark());    \u002F\u002F \"woof\" (own property)\nconsole.log(dog.breathe());  \u002F\u002F \"breathing\" (inherited from animal via prototype chain)\n\u002F\u002F Lookup: dog.breathe → dog (not found) → animal (found!) → return\n\n\u002F\u002F ── Object.create: explicit prototype ──\nconst obj = Object.create({ inherited: \"yes\" });\nconsole.log(obj.inherited);  \u002F\u002F \"yes\" (from prototype)\nconsole.log(Object.hasOwn(obj, \"inherited\"));  \u002F\u002F false (inherited, not own)\nconsole.log(\"inherited\" in obj);  \u002F\u002F true (in includes prototype chain)\n\n\u002F\u002F ── __proto__ vs Object.getPrototypeOf ──\nconst proto = { x: 1 };\nconst child = Object.create(proto);\nconsole.log(child.__proto__ === proto);  \u002F\u002F true (__proto__ is the getter)\nconsole.log(Object.getPrototypeOf(child) === proto);  \u002F\u002F true (preferred API)\n\u002F\u002F ⚠️ __proto__ is deprecated (use Object.getPrototypeOf \u002F Object.setPrototypeOf)\n\u002F\u002F ⚠️ __proto__ on object literals: { __proto__: proto } sets the prototype (ES2015+)\n\n\u002F\u002F ── Object.create(null): no prototype (pure dictionary) ──\nconst dict = Object.create(null);  \u002F\u002F [[Prototype]] is null\n\u002F\u002F dict.hasOwnProperty → undefined (no Object.prototype methods!)\n\u002F\u002F Useful for hash maps without prototype pollution:\ndict.key = \"value\";\n\u002F\u002F dict.constructor;  \u002F\u002F undefined (no Object.prototype)\n\u002F\u002F dict.toString();  \u002F\u002F TypeError: dict.toString is not a function\n",[30,982,983,988,993,997,1022,1042,1065,1069,1086,1102,1107,1111,1116,1136,1148,1170,1188,1192,1197,1213,1229,1250,1271,1276,1281,1285,1290,1314,1319,1324,1336,1344],{"__ignoreMap":28},[33,984,985],{"class":35,"line":36},[33,986,987],{"class":39},"\u002F\u002F ── Every object has an internal [[Prototype]] link (accessible via __proto__ or Object.getPrototypeOf) ──\n",[33,989,990],{"class":35,"line":43},[33,991,992],{"class":39},"\u002F\u002F Property lookup follows the prototype chain until found or null is reached.\n",[33,994,995],{"class":35,"line":49},[33,996,59],{"emptyLinePlaceholder":58},[33,998,999,1001,1004,1006,1009,1012,1014,1016,1019],{"class":35,"line":55},[33,1000,72],{"class":71},[33,1002,1003],{"class":75}," animal",[33,1005,79],{"class":71},[33,1007,1008],{"class":82}," { ",[33,1010,1011],{"class":107},"breathe",[33,1013,569],{"class":82},[33,1015,572],{"class":71},[33,1017,1018],{"class":120}," \"breathing\"",[33,1020,1021],{"class":82},"; } };\n",[33,1023,1024,1026,1029,1031,1033,1036,1039],{"class":35,"line":62},[33,1025,72],{"class":71},[33,1027,1028],{"class":75}," dog",[33,1030,79],{"class":71},[33,1032,716],{"class":82},[33,1034,1035],{"class":107},"create",[33,1037,1038],{"class":82},"(animal);  ",[33,1040,1041],{"class":39},"\u002F\u002F dog.__proto__ = animal\n",[33,1043,1044,1047,1050,1052,1055,1057,1059,1062],{"class":35,"line":68},[33,1045,1046],{"class":82},"dog.",[33,1048,1049],{"class":107},"bark",[33,1051,79],{"class":71},[33,1053,1054],{"class":71}," function",[33,1056,569],{"class":82},[33,1058,572],{"class":71},[33,1060,1061],{"class":120}," \"woof\"",[33,1063,1064],{"class":82},"; };\n",[33,1066,1067],{"class":35,"line":86},[33,1068,59],{"emptyLinePlaceholder":58},[33,1070,1071,1073,1075,1078,1080,1083],{"class":35,"line":101},[33,1072,104],{"class":82},[33,1074,108],{"class":107},[33,1076,1077],{"class":82},"(dog.",[33,1079,1049],{"class":107},[33,1081,1082],{"class":82},"());    ",[33,1084,1085],{"class":39},"\u002F\u002F \"woof\" (own property)\n",[33,1087,1088,1090,1092,1094,1096,1099],{"class":35,"line":127},[33,1089,104],{"class":82},[33,1091,108],{"class":107},[33,1093,1077],{"class":82},[33,1095,1011],{"class":107},[33,1097,1098],{"class":82},"());  ",[33,1100,1101],{"class":39},"\u002F\u002F \"breathing\" (inherited from animal via prototype chain)\n",[33,1103,1104],{"class":35,"line":133},[33,1105,1106],{"class":39},"\u002F\u002F Lookup: dog.breathe → dog (not found) → animal (found!) → return\n",[33,1108,1109],{"class":35,"line":139},[33,1110,59],{"emptyLinePlaceholder":58},[33,1112,1113],{"class":35,"line":144},[33,1114,1115],{"class":39},"\u002F\u002F ── Object.create: explicit prototype ──\n",[33,1117,1118,1120,1122,1124,1126,1128,1131,1134],{"class":35,"line":150},[33,1119,72],{"class":71},[33,1121,76],{"class":75},[33,1123,79],{"class":71},[33,1125,716],{"class":82},[33,1127,1035],{"class":107},[33,1129,1130],{"class":82},"({ inherited: ",[33,1132,1133],{"class":120},"\"yes\"",[33,1135,287],{"class":82},[33,1137,1138,1140,1142,1145],{"class":35,"line":167},[33,1139,104],{"class":82},[33,1141,108],{"class":107},[33,1143,1144],{"class":82},"(obj.inherited);  ",[33,1146,1147],{"class":39},"\u002F\u002F \"yes\" (from prototype)\n",[33,1149,1150,1152,1154,1156,1159,1161,1164,1167],{"class":35,"line":179},[33,1151,104],{"class":82},[33,1153,108],{"class":107},[33,1155,111],{"class":82},[33,1157,1158],{"class":107},"hasOwn",[33,1160,117],{"class":82},[33,1162,1163],{"class":120},"\"inherited\"",[33,1165,1166],{"class":82},"));  ",[33,1168,1169],{"class":39},"\u002F\u002F false (inherited, not own)\n",[33,1171,1172,1174,1176,1178,1180,1182,1185],{"class":35,"line":185},[33,1173,104],{"class":82},[33,1175,108],{"class":107},[33,1177,584],{"class":82},[33,1179,1163],{"class":120},[33,1181,372],{"class":71},[33,1183,1184],{"class":82}," obj);  ",[33,1186,1187],{"class":39},"\u002F\u002F true (in includes prototype chain)\n",[33,1189,1190],{"class":35,"line":191},[33,1191,59],{"emptyLinePlaceholder":58},[33,1193,1194],{"class":35,"line":197},[33,1195,1196],{"class":39},"\u002F\u002F ── __proto__ vs Object.getPrototypeOf ──\n",[33,1198,1199,1201,1204,1206,1209,1211],{"class":35,"line":203},[33,1200,72],{"class":71},[33,1202,1203],{"class":75}," proto",[33,1205,79],{"class":71},[33,1207,1208],{"class":82}," { x: ",[33,1210,278],{"class":75},[33,1212,331],{"class":82},[33,1214,1215,1217,1220,1222,1224,1226],{"class":35,"line":220},[33,1216,72],{"class":71},[33,1218,1219],{"class":75}," child",[33,1221,79],{"class":71},[33,1223,716],{"class":82},[33,1225,1035],{"class":107},[33,1227,1228],{"class":82},"(proto);\n",[33,1230,1231,1233,1235,1238,1241,1244,1247],{"class":35,"line":226},[33,1232,104],{"class":82},[33,1234,108],{"class":107},[33,1236,1237],{"class":82},"(child.",[33,1239,1240],{"class":75},"__proto__",[33,1242,1243],{"class":71}," ===",[33,1245,1246],{"class":82}," proto);  ",[33,1248,1249],{"class":39},"\u002F\u002F true (__proto__ is the getter)\n",[33,1251,1252,1254,1256,1258,1261,1264,1266,1268],{"class":35,"line":232},[33,1253,104],{"class":82},[33,1255,108],{"class":107},[33,1257,111],{"class":82},[33,1259,1260],{"class":107},"getPrototypeOf",[33,1262,1263],{"class":82},"(child) ",[33,1265,884],{"class":71},[33,1267,1246],{"class":82},[33,1269,1270],{"class":39},"\u002F\u002F true (preferred API)\n",[33,1272,1273],{"class":35,"line":237},[33,1274,1275],{"class":39},"\u002F\u002F ⚠️ __proto__ is deprecated (use Object.getPrototypeOf \u002F Object.setPrototypeOf)\n",[33,1277,1278],{"class":35,"line":243},[33,1279,1280],{"class":39},"\u002F\u002F ⚠️ __proto__ on object literals: { __proto__: proto } sets the prototype (ES2015+)\n",[33,1282,1283],{"class":35,"line":251},[33,1284,59],{"emptyLinePlaceholder":58},[33,1286,1287],{"class":35,"line":263},[33,1288,1289],{"class":39},"\u002F\u002F ── Object.create(null): no prototype (pure dictionary) ──\n",[33,1291,1292,1294,1297,1299,1301,1303,1305,1308,1311],{"class":35,"line":290},[33,1293,72],{"class":71},[33,1295,1296],{"class":75}," dict",[33,1298,79],{"class":71},[33,1300,716],{"class":82},[33,1302,1035],{"class":107},[33,1304,584],{"class":82},[33,1306,1307],{"class":75},"null",[33,1309,1310],{"class":82},");  ",[33,1312,1313],{"class":39},"\u002F\u002F [[Prototype]] is null\n",[33,1315,1316],{"class":35,"line":299},[33,1317,1318],{"class":39},"\u002F\u002F dict.hasOwnProperty → undefined (no Object.prototype methods!)\n",[33,1320,1321],{"class":35,"line":305},[33,1322,1323],{"class":39},"\u002F\u002F Useful for hash maps without prototype pollution:\n",[33,1325,1326,1329,1331,1334],{"class":35,"line":310},[33,1327,1328],{"class":82},"dict.key ",[33,1330,92],{"class":71},[33,1332,1333],{"class":120}," \"value\"",[33,1335,98],{"class":82},[33,1337,1338,1341],{"class":35,"line":316},[33,1339,1340],{"class":39},"\u002F\u002F dict.constructor;",[33,1342,1343],{"class":39},"  \u002F\u002F undefined (no Object.prototype)\n",[33,1345,1346,1349],{"class":35,"line":334},[33,1347,1348],{"class":39},"\u002F\u002F dict.toString();",[33,1350,1351],{"class":39},"  \u002F\u002F TypeError: dict.toString is not a function\n",[15,1353,1355],{"id":1354},"production-pattern-immutable-configuration-with-proxies","Production Pattern: Immutable Configuration with Proxies",[20,1357,1358],{"language":22},[24,1359,1361],{"className":26,"code":1360,"language":22,"meta":28,"style":28},"\u002F\u002F ── Deep immutability via Proxy (prevents any mutation, including nested) ──\nfunction immutable(target) {\n    return new Proxy(target, {\n        get(obj, prop, receiver) {\n            \u002F\u002F Return proxied nested objects (so they're also immutable)\n            const value = Reflect.get(obj, prop, receiver);\n            if (value && typeof value === \"object\") {\n                return immutable(value);  \u002F\u002F wrap nested objects\n            }\n            return value;\n        },\n        set() {\n            throw new TypeError(\"Cannot modify immutable object\");\n        },\n        deleteProperty() {\n            throw new TypeError(\"Cannot delete from immutable object\");\n        },\n        defineProperty() {\n            throw new TypeError(\"Cannot define property on immutable object\");\n        },\n    });\n}\n\nconst config = immutable({\n    server: { host: \"localhost\", port: 3000 },\n    features: [\"auth\", \"logging\"],\n});\n\n\u002F\u002F config.server.port = 9999;  \u002F\u002F TypeError: Cannot modify immutable object\n\u002F\u002F config.features.push(\"x\");  \u002F\u002F TypeError (push tries to set index — blocked by proxy)\nconsole.log(config.server.port);  \u002F\u002F 3000 (read works, write blocked)\n",[30,1362,1363,1368,1382,1394,1416,1421,1439,1458,1470,1475,1483,1488,1496,1514,1518,1525,1540,1544,1551,1566,1570,1575,1579,1583,1595,1607,1623,1627,1631,1639,1647],{"__ignoreMap":28},[33,1364,1365],{"class":35,"line":36},[33,1366,1367],{"class":39},"\u002F\u002F ── Deep immutability via Proxy (prevents any mutation, including nested) ──\n",[33,1369,1370,1372,1375,1377,1380],{"class":35,"line":43},[33,1371,795],{"class":71},[33,1373,1374],{"class":107}," immutable",[33,1376,584],{"class":82},[33,1378,1379],{"class":587},"target",[33,1381,806],{"class":82},[33,1383,1384,1386,1388,1391],{"class":35,"line":49},[33,1385,915],{"class":71},[33,1387,611],{"class":71},[33,1389,1390],{"class":107}," Proxy",[33,1392,1393],{"class":82},"(target, {\n",[33,1395,1396,1399,1401,1403,1406,1409,1411,1414],{"class":35,"line":55},[33,1397,1398],{"class":107},"        get",[33,1400,584],{"class":82},[33,1402,803],{"class":587},[33,1404,1405],{"class":82},", ",[33,1407,1408],{"class":587},"prop",[33,1410,1405],{"class":82},[33,1412,1413],{"class":587},"receiver",[33,1415,806],{"class":82},[33,1417,1418],{"class":35,"line":62},[33,1419,1420],{"class":39},"            \u002F\u002F Return proxied nested objects (so they're also immutable)\n",[33,1422,1423,1426,1428,1430,1433,1436],{"class":35,"line":68},[33,1424,1425],{"class":71},"            const",[33,1427,859],{"class":75},[33,1429,79],{"class":71},[33,1431,1432],{"class":82}," Reflect.",[33,1434,1435],{"class":107},"get",[33,1437,1438],{"class":82},"(obj, prop, receiver);\n",[33,1440,1441,1444,1446,1448,1450,1452,1454,1456],{"class":35,"line":86},[33,1442,1443],{"class":71},"            if",[33,1445,872],{"class":82},[33,1447,875],{"class":71},[33,1449,878],{"class":71},[33,1451,881],{"class":82},[33,1453,884],{"class":71},[33,1455,887],{"class":120},[33,1457,806],{"class":82},[33,1459,1460,1463,1465,1467],{"class":35,"line":101},[33,1461,1462],{"class":71},"                return",[33,1464,1374],{"class":107},[33,1466,897],{"class":82},[33,1468,1469],{"class":39},"\u002F\u002F wrap nested objects\n",[33,1471,1472],{"class":35,"line":127},[33,1473,1474],{"class":82},"            }\n",[33,1476,1477,1480],{"class":35,"line":133},[33,1478,1479],{"class":71},"            return",[33,1481,1482],{"class":82}," value;\n",[33,1484,1485],{"class":35,"line":139},[33,1486,1487],{"class":82},"        },\n",[33,1489,1490,1493],{"class":35,"line":144},[33,1491,1492],{"class":107},"        set",[33,1494,1495],{"class":82},"() {\n",[33,1497,1498,1501,1503,1506,1508,1511],{"class":35,"line":150},[33,1499,1500],{"class":71},"            throw",[33,1502,611],{"class":71},[33,1504,1505],{"class":107}," TypeError",[33,1507,584],{"class":82},[33,1509,1510],{"class":120},"\"Cannot modify immutable object\"",[33,1512,1513],{"class":82},");\n",[33,1515,1516],{"class":35,"line":167},[33,1517,1487],{"class":82},[33,1519,1520,1523],{"class":35,"line":179},[33,1521,1522],{"class":107},"        deleteProperty",[33,1524,1495],{"class":82},[33,1526,1527,1529,1531,1533,1535,1538],{"class":35,"line":185},[33,1528,1500],{"class":71},[33,1530,611],{"class":71},[33,1532,1505],{"class":107},[33,1534,584],{"class":82},[33,1536,1537],{"class":120},"\"Cannot delete from immutable object\"",[33,1539,1513],{"class":82},[33,1541,1542],{"class":35,"line":191},[33,1543,1487],{"class":82},[33,1545,1546,1549],{"class":35,"line":197},[33,1547,1548],{"class":107},"        defineProperty",[33,1550,1495],{"class":82},[33,1552,1553,1555,1557,1559,1561,1564],{"class":35,"line":203},[33,1554,1500],{"class":71},[33,1556,611],{"class":71},[33,1558,1505],{"class":107},[33,1560,584],{"class":82},[33,1562,1563],{"class":120},"\"Cannot define property on immutable object\"",[33,1565,1513],{"class":82},[33,1567,1568],{"class":35,"line":220},[33,1569,1487],{"class":82},[33,1571,1572],{"class":35,"line":226},[33,1573,1574],{"class":82},"    });\n",[33,1576,1577],{"class":35,"line":232},[33,1578,930],{"class":82},[33,1580,1581],{"class":35,"line":237},[33,1582,59],{"emptyLinePlaceholder":58},[33,1584,1585,1587,1589,1591,1593],{"class":35,"line":243},[33,1586,72],{"class":71},[33,1588,711],{"class":75},[33,1590,79],{"class":71},[33,1592,1374],{"class":107},[33,1594,722],{"class":82},[33,1596,1597,1599,1601,1603,1605],{"class":35,"line":251},[33,1598,727],{"class":82},[33,1600,730],{"class":120},[33,1602,733],{"class":82},[33,1604,736],{"class":75},[33,1606,739],{"class":82},[33,1608,1609,1612,1615,1617,1620],{"class":35,"line":263},[33,1610,1611],{"class":82},"    features: [",[33,1613,1614],{"class":120},"\"auth\"",[33,1616,1405],{"class":82},[33,1618,1619],{"class":120},"\"logging\"",[33,1621,1622],{"class":82},"],\n",[33,1624,1625],{"class":35,"line":290},[33,1626,200],{"class":82},[33,1628,1629],{"class":35,"line":299},[33,1630,59],{"emptyLinePlaceholder":58},[33,1632,1633,1636],{"class":35,"line":305},[33,1634,1635],{"class":39},"\u002F\u002F config.server.port = 9999;",[33,1637,1638],{"class":39},"  \u002F\u002F TypeError: Cannot modify immutable object\n",[33,1640,1641,1644],{"class":35,"line":310},[33,1642,1643],{"class":39},"\u002F\u002F config.features.push(\"x\");",[33,1645,1646],{"class":39},"  \u002F\u002F TypeError (push tries to set index — blocked by proxy)\n",[33,1648,1649,1651,1653,1655],{"class":35,"line":316},[33,1650,104],{"class":82},[33,1652,108],{"class":107},[33,1654,768],{"class":82},[33,1656,1657],{"class":39},"\u002F\u002F 3000 (read works, write blocked)\n",[15,1659,1661],{"id":1660},"object-cloning-shallow-vs-deep","Object Cloning: Shallow vs Deep",[20,1663,1664],{"language":22},[24,1665,1667],{"className":26,"code":1666,"language":22,"meta":28,"style":28},"\u002F\u002F ── Shallow copy: copies top-level properties, shares nested references ──\nconst original = { a: 1, nested: { b: 2 } };\n\n\u002F\u002F Method 1: spread (shallow)\nconst shallow1 = { ...original };\nshallow1.a = 99;           \u002F\u002F doesn't affect original (top-level copy)\nshallow1.nested.b = 99;   \u002F\u002F DOES affect original (shared reference!)\nconsole.log(original.nested.b);  \u002F\u002F 99 — shared mutation!\n\n\u002F\u002F Method 2: Object.assign (shallow)\nconst shallow2 = Object.assign({}, original);\n\u002F\u002F Same issue: nested objects are shared.\n\n\u002F\u002F ── Deep copy: recursively copies all nested objects ──\n\u002F\u002F Method 1: structuredClone (modern, handles most types, NOT functions)\nconst deep1 = structuredClone(original);\ndeep1.nested.b = 99;\nconsole.log(original.nested.b);  \u002F\u002F 2 — unaffected (true deep copy)\n\n\u002F\u002F Method 2: JSON.parse(JSON.stringify()) (legacy — loses functions, dates, Maps, etc.)\nconst deep2 = JSON.parse(JSON.stringify(original));\n\u002F\u002F ⚠️ Lossy: undefined → omitted, Date → string, Map\u002FSet → {}, NaN → null, functions → omitted\n\n\u002F\u002F Method 3: manual recursive clone (full control)\nfunction deepClone(obj, cache = new WeakMap()) {\n    if (obj === null || typeof obj !== \"object\") return obj;  \u002F\u002F primitives\n    if (obj instanceof Date) return new Date(obj);\n    if (obj instanceof RegExp) return new RegExp(obj);\n    if (obj instanceof Map) return new Map([...obj].map(([k, v]) => [deepClone(k), deepClone(v)]));\n    if (obj instanceof Set) return new Set([...obj].map(deepClone));\n    if (cache.has(obj)) return cache.get(obj);  \u002F\u002F circular reference guard\n\n    const clone = Array.isArray(obj) ? [] : Object.create(Object.getPrototypeOf(obj));\n    cache.set(obj, clone);  \u002F\u002F store before recursing (handle circular refs)\n    for (const key of Reflect.ownKeys(obj)) {\n        clone[key] = deepClone(obj[key], cache);\n    }\n    return clone;\n}\n",[30,1668,1669,1674,1695,1699,1704,1721,1737,1752,1764,1768,1773,1790,1795,1799,1804,1809,1824,1835,1846,1850,1855,1886,1891,1895,1900,1926,1962,1984,2005,2065,2095,2120,2124,2162,2176,2195,2207,2211,2218],{"__ignoreMap":28},[33,1670,1671],{"class":35,"line":36},[33,1672,1673],{"class":39},"\u002F\u002F ── Shallow copy: copies top-level properties, shares nested references ──\n",[33,1675,1676,1678,1681,1683,1685,1687,1690,1692],{"class":35,"line":43},[33,1677,72],{"class":71},[33,1679,1680],{"class":75}," original",[33,1682,79],{"class":71},[33,1684,326],{"class":82},[33,1686,278],{"class":75},[33,1688,1689],{"class":82},", nested: { b: ",[33,1691,173],{"class":75},[33,1693,1694],{"class":82}," } };\n",[33,1696,1697],{"class":35,"line":49},[33,1698,59],{"emptyLinePlaceholder":58},[33,1700,1701],{"class":35,"line":55},[33,1702,1703],{"class":39},"\u002F\u002F Method 1: spread (shallow)\n",[33,1705,1706,1708,1711,1713,1715,1718],{"class":35,"line":62},[33,1707,72],{"class":71},[33,1709,1710],{"class":75}," shallow1",[33,1712,79],{"class":71},[33,1714,1008],{"class":82},[33,1716,1717],{"class":71},"...",[33,1719,1720],{"class":82},"original };\n",[33,1722,1723,1726,1728,1731,1734],{"class":35,"line":68},[33,1724,1725],{"class":82},"shallow1.a ",[33,1727,92],{"class":71},[33,1729,1730],{"class":75}," 99",[33,1732,1733],{"class":82},";           ",[33,1735,1736],{"class":39},"\u002F\u002F doesn't affect original (top-level copy)\n",[33,1738,1739,1742,1744,1746,1749],{"class":35,"line":86},[33,1740,1741],{"class":82},"shallow1.nested.b ",[33,1743,92],{"class":71},[33,1745,1730],{"class":75},[33,1747,1748],{"class":82},";   ",[33,1750,1751],{"class":39},"\u002F\u002F DOES affect original (shared reference!)\n",[33,1753,1754,1756,1758,1761],{"class":35,"line":101},[33,1755,104],{"class":82},[33,1757,108],{"class":107},[33,1759,1760],{"class":82},"(original.nested.b);  ",[33,1762,1763],{"class":39},"\u002F\u002F 99 — shared mutation!\n",[33,1765,1766],{"class":35,"line":127},[33,1767,59],{"emptyLinePlaceholder":58},[33,1769,1770],{"class":35,"line":133},[33,1771,1772],{"class":39},"\u002F\u002F Method 2: Object.assign (shallow)\n",[33,1774,1775,1777,1780,1782,1784,1787],{"class":35,"line":139},[33,1776,72],{"class":71},[33,1778,1779],{"class":75}," shallow2",[33,1781,79],{"class":71},[33,1783,716],{"class":82},[33,1785,1786],{"class":107},"assign",[33,1788,1789],{"class":82},"({}, original);\n",[33,1791,1792],{"class":35,"line":144},[33,1793,1794],{"class":39},"\u002F\u002F Same issue: nested objects are shared.\n",[33,1796,1797],{"class":35,"line":150},[33,1798,59],{"emptyLinePlaceholder":58},[33,1800,1801],{"class":35,"line":167},[33,1802,1803],{"class":39},"\u002F\u002F ── Deep copy: recursively copies all nested objects ──\n",[33,1805,1806],{"class":35,"line":179},[33,1807,1808],{"class":39},"\u002F\u002F Method 1: structuredClone (modern, handles most types, NOT functions)\n",[33,1810,1811,1813,1816,1818,1821],{"class":35,"line":185},[33,1812,72],{"class":71},[33,1814,1815],{"class":75}," deep1",[33,1817,79],{"class":71},[33,1819,1820],{"class":107}," structuredClone",[33,1822,1823],{"class":82},"(original);\n",[33,1825,1826,1829,1831,1833],{"class":35,"line":191},[33,1827,1828],{"class":82},"deep1.nested.b ",[33,1830,92],{"class":71},[33,1832,1730],{"class":75},[33,1834,98],{"class":82},[33,1836,1837,1839,1841,1843],{"class":35,"line":197},[33,1838,104],{"class":82},[33,1840,108],{"class":107},[33,1842,1760],{"class":82},[33,1844,1845],{"class":39},"\u002F\u002F 2 — unaffected (true deep copy)\n",[33,1847,1848],{"class":35,"line":203},[33,1849,59],{"emptyLinePlaceholder":58},[33,1851,1852],{"class":35,"line":220},[33,1853,1854],{"class":39},"\u002F\u002F Method 2: JSON.parse(JSON.stringify()) (legacy — loses functions, dates, Maps, etc.)\n",[33,1856,1857,1859,1862,1864,1867,1870,1873,1875,1878,1880,1883],{"class":35,"line":226},[33,1858,72],{"class":71},[33,1860,1861],{"class":75}," deep2",[33,1863,79],{"class":71},[33,1865,1866],{"class":75}," JSON",[33,1868,1869],{"class":82},".",[33,1871,1872],{"class":107},"parse",[33,1874,584],{"class":82},[33,1876,1877],{"class":75},"JSON",[33,1879,1869],{"class":82},[33,1881,1882],{"class":107},"stringify",[33,1884,1885],{"class":82},"(original));\n",[33,1887,1888],{"class":35,"line":232},[33,1889,1890],{"class":39},"\u002F\u002F ⚠️ Lossy: undefined → omitted, Date → string, Map\u002FSet → {}, NaN → null, functions → omitted\n",[33,1892,1893],{"class":35,"line":237},[33,1894,59],{"emptyLinePlaceholder":58},[33,1896,1897],{"class":35,"line":243},[33,1898,1899],{"class":39},"\u002F\u002F Method 3: manual recursive clone (full control)\n",[33,1901,1902,1904,1907,1909,1911,1913,1916,1918,1920,1923],{"class":35,"line":251},[33,1903,795],{"class":71},[33,1905,1906],{"class":107}," deepClone",[33,1908,584],{"class":82},[33,1910,803],{"class":587},[33,1912,1405],{"class":82},[33,1914,1915],{"class":587},"cache",[33,1917,79],{"class":71},[33,1919,611],{"class":71},[33,1921,1922],{"class":107}," WeakMap",[33,1924,1925],{"class":82},"()) {\n",[33,1927,1928,1931,1934,1936,1939,1942,1944,1947,1950,1952,1954,1956,1959],{"class":35,"line":263},[33,1929,1930],{"class":71},"    if",[33,1932,1933],{"class":82}," (obj ",[33,1935,884],{"class":71},[33,1937,1938],{"class":75}," null",[33,1940,1941],{"class":71}," ||",[33,1943,878],{"class":71},[33,1945,1946],{"class":82}," obj ",[33,1948,1949],{"class":71},"!==",[33,1951,887],{"class":120},[33,1953,605],{"class":82},[33,1955,572],{"class":71},[33,1957,1958],{"class":82}," obj;  ",[33,1960,1961],{"class":39},"\u002F\u002F primitives\n",[33,1963,1964,1966,1968,1971,1974,1976,1978,1980,1982],{"class":35,"line":290},[33,1965,1930],{"class":71},[33,1967,1933],{"class":82},[33,1969,1970],{"class":71},"instanceof",[33,1972,1973],{"class":107}," Date",[33,1975,605],{"class":82},[33,1977,572],{"class":71},[33,1979,611],{"class":71},[33,1981,1973],{"class":107},[33,1983,828],{"class":82},[33,1985,1986,1988,1990,1992,1995,1997,1999,2001,2003],{"class":35,"line":299},[33,1987,1930],{"class":71},[33,1989,1933],{"class":82},[33,1991,1970],{"class":71},[33,1993,1994],{"class":107}," RegExp",[33,1996,605],{"class":82},[33,1998,572],{"class":71},[33,2000,611],{"class":71},[33,2002,1994],{"class":107},[33,2004,828],{"class":82},[33,2006,2007,2009,2011,2013,2016,2018,2020,2022,2024,2027,2029,2032,2035,2038,2041,2043,2045,2048,2051,2054,2057,2060,2062],{"class":35,"line":305},[33,2008,1930],{"class":71},[33,2010,1933],{"class":82},[33,2012,1970],{"class":71},[33,2014,2015],{"class":107}," Map",[33,2017,605],{"class":82},[33,2019,572],{"class":71},[33,2021,611],{"class":71},[33,2023,2015],{"class":107},[33,2025,2026],{"class":82},"([",[33,2028,1717],{"class":71},[33,2030,2031],{"class":82},"obj].",[33,2033,2034],{"class":107},"map",[33,2036,2037],{"class":82},"(([",[33,2039,2040],{"class":587},"k",[33,2042,1405],{"class":82},[33,2044,588],{"class":587},[33,2046,2047],{"class":82},"]) ",[33,2049,2050],{"class":71},"=>",[33,2052,2053],{"class":82}," [",[33,2055,2056],{"class":107},"deepClone",[33,2058,2059],{"class":82},"(k), ",[33,2061,2056],{"class":107},[33,2063,2064],{"class":82},"(v)]));\n",[33,2066,2067,2069,2071,2073,2076,2078,2080,2082,2084,2086,2088,2090,2092],{"class":35,"line":310},[33,2068,1930],{"class":71},[33,2070,1933],{"class":82},[33,2072,1970],{"class":71},[33,2074,2075],{"class":107}," Set",[33,2077,605],{"class":82},[33,2079,572],{"class":71},[33,2081,611],{"class":71},[33,2083,2075],{"class":107},[33,2085,2026],{"class":82},[33,2087,1717],{"class":71},[33,2089,2031],{"class":82},[33,2091,2034],{"class":107},[33,2093,2094],{"class":82},"(deepClone));\n",[33,2096,2097,2099,2102,2105,2108,2110,2113,2115,2117],{"class":35,"line":316},[33,2098,1930],{"class":71},[33,2100,2101],{"class":82}," (cache.",[33,2103,2104],{"class":107},"has",[33,2106,2107],{"class":82},"(obj)) ",[33,2109,572],{"class":71},[33,2111,2112],{"class":82}," cache.",[33,2114,1435],{"class":107},[33,2116,922],{"class":82},[33,2118,2119],{"class":39},"\u002F\u002F circular reference guard\n",[33,2121,2122],{"class":35,"line":334},[33,2123,59],{"emptyLinePlaceholder":58},[33,2125,2126,2128,2131,2133,2136,2139,2142,2145,2148,2151,2153,2155,2157,2159],{"class":35,"line":358},[33,2127,816],{"class":71},[33,2129,2130],{"class":75}," clone",[33,2132,79],{"class":71},[33,2134,2135],{"class":82}," Array.",[33,2137,2138],{"class":107},"isArray",[33,2140,2141],{"class":82},"(obj) ",[33,2143,2144],{"class":71},"?",[33,2146,2147],{"class":82}," [] ",[33,2149,2150],{"class":71},":",[33,2152,716],{"class":82},[33,2154,1035],{"class":107},[33,2156,111],{"class":82},[33,2158,1260],{"class":107},[33,2160,2161],{"class":82},"(obj));\n",[33,2163,2164,2167,2170,2173],{"class":35,"line":386},[33,2165,2166],{"class":82},"    cache.",[33,2168,2169],{"class":107},"set",[33,2171,2172],{"class":82},"(obj, clone);  ",[33,2174,2175],{"class":39},"\u002F\u002F store before recursing (handle circular refs)\n",[33,2177,2178,2180,2182,2184,2186,2188,2190,2192],{"class":35,"line":404},[33,2179,838],{"class":71},[33,2181,364],{"class":82},[33,2183,72],{"class":71},[33,2185,369],{"class":75},[33,2187,848],{"class":71},[33,2189,1432],{"class":82},[33,2191,431],{"class":107},[33,2193,2194],{"class":82},"(obj)) {\n",[33,2196,2197,2200,2202,2204],{"class":35,"line":421},[33,2198,2199],{"class":82},"        clone[key] ",[33,2201,92],{"class":71},[33,2203,1906],{"class":107},[33,2205,2206],{"class":82},"(obj[key], cache);\n",[33,2208,2209],{"class":35,"line":439},[33,2210,910],{"class":82},[33,2212,2213,2215],{"class":35,"line":444},[33,2214,915],{"class":71},[33,2216,2217],{"class":82}," clone;\n",[33,2219,2220],{"class":35,"line":450},[33,2221,930],{"class":82},[15,2223,2225],{"id":2224},"tips-tricks","💡 Tips & Tricks",[20,2227,2228],{"language":22},[24,2229,2231],{"className":26,"code":2230,"language":22,"meta":28,"style":28},"\u002F\u002F ── Object.keys \u002F values \u002F entries (own enumerable string-keyed only) ──\nconst obj = { a: 1, b: 2, [Symbol(\"c\")]: 3 };\nObject.keys(obj);     \u002F\u002F [\"a\", \"b\"] (string keys only, own, enumerable)\nObject.values(obj);   \u002F\u002F [1, 2]\nObject.entries(obj);  \u002F\u002F [[\"a\", 1], [\"b\", 2]]\n\u002F\u002F Symbols and non-enumerable properties are excluded.\n\u002F\u002F Use Reflect.ownKeys(obj) for ALL keys (strings + symbols, enumerable + non-enumerable).\n\n\u002F\u002F ── Computed property names (ES2015) ──\nconst key = \"dynamic\";\nconst obj2 = { [key]: 1, [`${key}Prop`]: 2 };\n\u002F\u002F { dynamic: 1, dynamicProp: 2 }\n\n\u002F\u002F ── Object shorthand (ES2015) ──\nconst x = 1, y = 2;\nconst obj3 = { x, y };  \u002F\u002F { x: 1, y: 2 } (shorthand: key = variable name)\n\n\u002F\u002F ── Method shorthand ──\nconst obj4 = {\n    method() { return \"hello\"; },  \u002F\u002F shorthand: no `function` keyword\n    \u002F\u002F equivalent to: method: function() { ... }\n};\n\n\u002F\u002F ── Optional chaining for safe property access ──\nconst value = obj?.nested?.deep?.value ?? \"default\";\n\n\u002F\u002F ── Object.groupBy (ES2024) ──\nconst items = [\n    { category: \"fruit\", name: \"apple\" },\n    { category: \"fruit\", name: \"banana\" },\n    { category: \"veg\", name: \"carrot\" },\n];\nconst grouped = Object.groupBy(items, item => item.category);\n\u002F\u002F { fruit: [{...}, {...}], veg: [{...}] }\n",[30,2232,2233,2238,2274,2286,2299,2311,2316,2321,2325,2330,2343,2374,2379,2383,2388,2411,2425,2429,2434,2445,2463,2468,2473,2477,2482,2501,2505,2510,2522,2538,2551,2565,2570,2596],{"__ignoreMap":28},[33,2234,2235],{"class":35,"line":36},[33,2236,2237],{"class":39},"\u002F\u002F ── Object.keys \u002F values \u002F entries (own enumerable string-keyed only) ──\n",[33,2239,2240,2242,2244,2246,2248,2250,2253,2255,2258,2261,2263,2266,2269,2272],{"class":35,"line":43},[33,2241,72],{"class":71},[33,2243,76],{"class":75},[33,2245,79],{"class":71},[33,2247,326],{"class":82},[33,2249,278],{"class":75},[33,2251,2252],{"class":82},", b: ",[33,2254,173],{"class":75},[33,2256,2257],{"class":82},", [",[33,2259,2260],{"class":107},"Symbol",[33,2262,584],{"class":82},[33,2264,2265],{"class":120},"\"c\"",[33,2267,2268],{"class":82},")]: ",[33,2270,2271],{"class":75},"3",[33,2273,331],{"class":82},[33,2275,2276,2278,2280,2283],{"class":35,"line":49},[33,2277,153],{"class":82},[33,2279,395],{"class":107},[33,2281,2282],{"class":82},"(obj);     ",[33,2284,2285],{"class":39},"\u002F\u002F [\"a\", \"b\"] (string keys only, own, enumerable)\n",[33,2287,2288,2290,2293,2296],{"class":35,"line":55},[33,2289,153],{"class":82},[33,2291,2292],{"class":107},"values",[33,2294,2295],{"class":82},"(obj);   ",[33,2297,2298],{"class":39},"\u002F\u002F [1, 2]\n",[33,2300,2301,2303,2306,2308],{"class":35,"line":62},[33,2302,153],{"class":82},[33,2304,2305],{"class":107},"entries",[33,2307,922],{"class":82},[33,2309,2310],{"class":39},"\u002F\u002F [[\"a\", 1], [\"b\", 2]]\n",[33,2312,2313],{"class":35,"line":68},[33,2314,2315],{"class":39},"\u002F\u002F Symbols and non-enumerable properties are excluded.\n",[33,2317,2318],{"class":35,"line":86},[33,2319,2320],{"class":39},"\u002F\u002F Use Reflect.ownKeys(obj) for ALL keys (strings + symbols, enumerable + non-enumerable).\n",[33,2322,2323],{"class":35,"line":101},[33,2324,59],{"emptyLinePlaceholder":58},[33,2326,2327],{"class":35,"line":127},[33,2328,2329],{"class":39},"\u002F\u002F ── Computed property names (ES2015) ──\n",[33,2331,2332,2334,2336,2338,2341],{"class":35,"line":133},[33,2333,72],{"class":71},[33,2335,369],{"class":75},[33,2337,79],{"class":71},[33,2339,2340],{"class":120}," \"dynamic\"",[33,2342,98],{"class":82},[33,2344,2345,2347,2349,2351,2354,2356,2358,2361,2364,2367,2370,2372],{"class":35,"line":139},[33,2346,72],{"class":71},[33,2348,256],{"class":75},[33,2350,79],{"class":71},[33,2352,2353],{"class":82}," { [key]: ",[33,2355,278],{"class":75},[33,2357,2257],{"class":82},[33,2359,2360],{"class":120},"`${",[33,2362,2363],{"class":82},"key",[33,2365,2366],{"class":120},"}Prop`",[33,2368,2369],{"class":82},"]: ",[33,2371,173],{"class":75},[33,2373,331],{"class":82},[33,2375,2376],{"class":35,"line":144},[33,2377,2378],{"class":39},"\u002F\u002F { dynamic: 1, dynamicProp: 2 }\n",[33,2380,2381],{"class":35,"line":150},[33,2382,59],{"emptyLinePlaceholder":58},[33,2384,2385],{"class":35,"line":167},[33,2386,2387],{"class":39},"\u002F\u002F ── Object shorthand (ES2015) ──\n",[33,2389,2390,2392,2395,2397,2399,2401,2404,2406,2409],{"class":35,"line":179},[33,2391,72],{"class":71},[33,2393,2394],{"class":75}," x",[33,2396,79],{"class":71},[33,2398,95],{"class":75},[33,2400,1405],{"class":82},[33,2402,2403],{"class":75},"y",[33,2405,79],{"class":71},[33,2407,2408],{"class":75}," 2",[33,2410,98],{"class":82},[33,2412,2413,2415,2417,2419,2422],{"class":35,"line":185},[33,2414,72],{"class":71},[33,2416,321],{"class":75},[33,2418,79],{"class":71},[33,2420,2421],{"class":82}," { x, y };  ",[33,2423,2424],{"class":39},"\u002F\u002F { x: 1, y: 2 } (shorthand: key = variable name)\n",[33,2426,2427],{"class":35,"line":191},[33,2428,59],{"emptyLinePlaceholder":58},[33,2430,2431],{"class":35,"line":197},[33,2432,2433],{"class":39},"\u002F\u002F ── Method shorthand ──\n",[33,2435,2436,2438,2440,2442],{"class":35,"line":203},[33,2437,72],{"class":71},[33,2439,455],{"class":75},[33,2441,79],{"class":71},[33,2443,2444],{"class":82}," {\n",[33,2446,2447,2450,2452,2454,2457,2460],{"class":35,"line":220},[33,2448,2449],{"class":107},"    method",[33,2451,569],{"class":82},[33,2453,572],{"class":71},[33,2455,2456],{"class":120}," \"hello\"",[33,2458,2459],{"class":82},"; },  ",[33,2461,2462],{"class":39},"\u002F\u002F shorthand: no `function` keyword\n",[33,2464,2465],{"class":35,"line":226},[33,2466,2467],{"class":39},"    \u002F\u002F equivalent to: method: function() { ... }\n",[33,2469,2470],{"class":35,"line":232},[33,2471,2472],{"class":82},"};\n",[33,2474,2475],{"class":35,"line":237},[33,2476,59],{"emptyLinePlaceholder":58},[33,2478,2479],{"class":35,"line":243},[33,2480,2481],{"class":39},"\u002F\u002F ── Optional chaining for safe property access ──\n",[33,2483,2484,2486,2488,2490,2493,2496,2499],{"class":35,"line":251},[33,2485,72],{"class":71},[33,2487,859],{"class":75},[33,2489,79],{"class":71},[33,2491,2492],{"class":82}," obj?.nested?.deep?.value ",[33,2494,2495],{"class":71},"??",[33,2497,2498],{"class":120}," \"default\"",[33,2500,98],{"class":82},[33,2502,2503],{"class":35,"line":263},[33,2504,59],{"emptyLinePlaceholder":58},[33,2506,2507],{"class":35,"line":290},[33,2508,2509],{"class":39},"\u002F\u002F ── Object.groupBy (ES2024) ──\n",[33,2511,2512,2514,2517,2519],{"class":35,"line":299},[33,2513,72],{"class":71},[33,2515,2516],{"class":75}," items",[33,2518,79],{"class":71},[33,2520,2521],{"class":82}," [\n",[33,2523,2524,2527,2530,2533,2536],{"class":35,"line":305},[33,2525,2526],{"class":82},"    { category: ",[33,2528,2529],{"class":120},"\"fruit\"",[33,2531,2532],{"class":82},", name: ",[33,2534,2535],{"class":120},"\"apple\"",[33,2537,739],{"class":82},[33,2539,2540,2542,2544,2546,2549],{"class":35,"line":310},[33,2541,2526],{"class":82},[33,2543,2529],{"class":120},[33,2545,2532],{"class":82},[33,2547,2548],{"class":120},"\"banana\"",[33,2550,739],{"class":82},[33,2552,2553,2555,2558,2560,2563],{"class":35,"line":316},[33,2554,2526],{"class":82},[33,2556,2557],{"class":120},"\"veg\"",[33,2559,2532],{"class":82},[33,2561,2562],{"class":120},"\"carrot\"",[33,2564,739],{"class":82},[33,2566,2567],{"class":35,"line":334},[33,2568,2569],{"class":82},"];\n",[33,2571,2572,2574,2577,2579,2581,2584,2587,2590,2593],{"class":35,"line":358},[33,2573,72],{"class":71},[33,2575,2576],{"class":75}," grouped",[33,2578,79],{"class":71},[33,2580,716],{"class":82},[33,2582,2583],{"class":107},"groupBy",[33,2585,2586],{"class":82},"(items, ",[33,2588,2589],{"class":587},"item",[33,2591,2592],{"class":71}," =>",[33,2594,2595],{"class":82}," item.category);\n",[33,2597,2598],{"class":35,"line":386},[33,2599,2600],{"class":39},"\u002F\u002F { fruit: [{...}, {...}], veg: [{...}] }\n",[15,2602,2604],{"id":2603},"️-edge-cases-gotchas","⚠️ Edge Cases & Gotchas",[20,2606,2607],{"language":22},[24,2608,2610],{"className":26,"code":2609,"language":22,"meta":28,"style":28},"\u002F\u002F ── Object.defineProperty defaults to false (not true) ──\n\u002F\u002F Assigning via `=` → all descriptors default to true.\n\u002F\u002F Defining via defineProperty → all descriptors default to FALSE.\nObject.defineProperty({}, \"x\", { value: 1 });\n\u002F\u002F writable: false, enumerable: false, configurable: false (all default to false!)\n\n\u002F\u002F ── `in` operator includes the prototype chain ──\nconst obj = Object.create({ inherited: true });\nconsole.log(\"inherited\" in obj);  \u002F\u002F true (checks prototype chain!)\nconsole.log(Object.hasOwn(obj, \"inherited\"));  \u002F\u002F false (own only)\n\u002F\u002F Use Object.hasOwn (or the deprecated obj.hasOwnProperty) to check own properties only.\n\n\u002F\u002F ── `Object.freeze` is shallow ──\nconst frozen = Object.freeze({ nested: { x: 1 } });\nfrozen.nested.x = 2;  \u002F\u002F works! (nested is not frozen)\n\n\u002F\u002F ── `JSON.stringify` skips non-enumerable and function-valued properties ──\nconst obj = { a: 1, fn() {} };\nObject.defineProperty(obj, \"hidden\", { value: 2, enumerable: false });\nJSON.stringify(obj);  \u002F\u002F '{\"a\":1}' — fn and hidden are excluded\n\n\u002F\u002F ── Getters are called by JSON.stringify (side effects) ──\nconst obj = {\n    _count: 0,\n    get count() { return ++this._count; },  \u002F\u002F each access increments!\n};\nJSON.stringify(obj);  \u002F\u002F calls count getter → _count becomes 1\nJSON.stringify(obj);  \u002F\u002F calls again → _count becomes 2\n\u002F\u002F Don't put side effects in getters!\n\n\u002F\u002F ── `Object.keys` order: integer-like keys first (sorted), then insertion order ──\nconst obj = { b: 1, 2: 2, a: 3, 1: 4 };\nObject.keys(obj);  \u002F\u002F [\"1\", \"2\", \"b\", \"a\"] — integer keys sorted first, then strings in insertion order\n\u002F\u002F (ES2020 guarantees this order for for...in, Object.keys, Object.values, Object.entries)\n",[30,2611,2612,2617,2622,2627,2644,2649,2653,2658,2676,2693,2712,2717,2721,2726,2747,2761,2765,2770,2790,2811,2824,2828,2833,2843,2853,2876,2880,2893,2906,2911,2915,2920,2958,2969],{"__ignoreMap":28},[33,2613,2614],{"class":35,"line":36},[33,2615,2616],{"class":39},"\u002F\u002F ── Object.defineProperty defaults to false (not true) ──\n",[33,2618,2619],{"class":35,"line":43},[33,2620,2621],{"class":39},"\u002F\u002F Assigning via `=` → all descriptors default to true.\n",[33,2623,2624],{"class":35,"line":49},[33,2625,2626],{"class":39},"\u002F\u002F Defining via defineProperty → all descriptors default to FALSE.\n",[33,2628,2629,2631,2633,2636,2638,2640,2642],{"class":35,"line":55},[33,2630,153],{"class":82},[33,2632,156],{"class":107},[33,2634,2635],{"class":82},"({}, ",[33,2637,121],{"class":120},[33,2639,275],{"class":82},[33,2641,278],{"class":75},[33,2643,287],{"class":82},[33,2645,2646],{"class":35,"line":62},[33,2647,2648],{"class":39},"\u002F\u002F writable: false, enumerable: false, configurable: false (all default to false!)\n",[33,2650,2651],{"class":35,"line":68},[33,2652,59],{"emptyLinePlaceholder":58},[33,2654,2655],{"class":35,"line":86},[33,2656,2657],{"class":39},"\u002F\u002F ── `in` operator includes the prototype chain ──\n",[33,2659,2660,2662,2664,2666,2668,2670,2672,2674],{"class":35,"line":101},[33,2661,72],{"class":71},[33,2663,76],{"class":75},[33,2665,79],{"class":71},[33,2667,716],{"class":82},[33,2669,1035],{"class":107},[33,2671,1130],{"class":82},[33,2673,636],{"class":75},[33,2675,287],{"class":82},[33,2677,2678,2680,2682,2684,2686,2688,2690],{"class":35,"line":127},[33,2679,104],{"class":82},[33,2681,108],{"class":107},[33,2683,584],{"class":82},[33,2685,1163],{"class":120},[33,2687,372],{"class":71},[33,2689,1184],{"class":82},[33,2691,2692],{"class":39},"\u002F\u002F true (checks prototype chain!)\n",[33,2694,2695,2697,2699,2701,2703,2705,2707,2709],{"class":35,"line":133},[33,2696,104],{"class":82},[33,2698,108],{"class":107},[33,2700,111],{"class":82},[33,2702,1158],{"class":107},[33,2704,117],{"class":82},[33,2706,1163],{"class":120},[33,2708,1166],{"class":82},[33,2710,2711],{"class":39},"\u002F\u002F false (own only)\n",[33,2713,2714],{"class":35,"line":139},[33,2715,2716],{"class":39},"\u002F\u002F Use Object.hasOwn (or the deprecated obj.hasOwnProperty) to check own properties only.\n",[33,2718,2719],{"class":35,"line":144},[33,2720,59],{"emptyLinePlaceholder":58},[33,2722,2723],{"class":35,"line":150},[33,2724,2725],{"class":39},"\u002F\u002F ── `Object.freeze` is shallow ──\n",[33,2727,2728,2730,2733,2735,2737,2739,2742,2744],{"class":35,"line":167},[33,2729,72],{"class":71},[33,2731,2732],{"class":75}," frozen",[33,2734,79],{"class":71},[33,2736,716],{"class":82},[33,2738,719],{"class":107},[33,2740,2741],{"class":82},"({ nested: { x: ",[33,2743,278],{"class":75},[33,2745,2746],{"class":82}," } });\n",[33,2748,2749,2752,2754,2756,2758],{"class":35,"line":179},[33,2750,2751],{"class":82},"frozen.nested.x ",[33,2753,92],{"class":71},[33,2755,2408],{"class":75},[33,2757,756],{"class":82},[33,2759,2760],{"class":39},"\u002F\u002F works! (nested is not frozen)\n",[33,2762,2763],{"class":35,"line":185},[33,2764,59],{"emptyLinePlaceholder":58},[33,2766,2767],{"class":35,"line":191},[33,2768,2769],{"class":39},"\u002F\u002F ── `JSON.stringify` skips non-enumerable and function-valued properties ──\n",[33,2771,2772,2774,2776,2778,2780,2782,2784,2787],{"class":35,"line":197},[33,2773,72],{"class":71},[33,2775,76],{"class":75},[33,2777,79],{"class":71},[33,2779,326],{"class":82},[33,2781,278],{"class":75},[33,2783,1405],{"class":82},[33,2785,2786],{"class":107},"fn",[33,2788,2789],{"class":82},"() {} };\n",[33,2791,2792,2794,2796,2798,2801,2803,2805,2807,2809],{"class":35,"line":203},[33,2793,153],{"class":82},[33,2795,156],{"class":107},[33,2797,117],{"class":82},[33,2799,2800],{"class":120},"\"hidden\"",[33,2802,275],{"class":82},[33,2804,173],{"class":75},[33,2806,351],{"class":82},[33,2808,284],{"class":75},[33,2810,287],{"class":82},[33,2812,2813,2815,2817,2819,2821],{"class":35,"line":220},[33,2814,1877],{"class":75},[33,2816,1869],{"class":82},[33,2818,1882],{"class":107},[33,2820,922],{"class":82},[33,2822,2823],{"class":39},"\u002F\u002F '{\"a\":1}' — fn and hidden are excluded\n",[33,2825,2826],{"class":35,"line":226},[33,2827,59],{"emptyLinePlaceholder":58},[33,2829,2830],{"class":35,"line":232},[33,2831,2832],{"class":39},"\u002F\u002F ── Getters are called by JSON.stringify (side effects) ──\n",[33,2834,2835,2837,2839,2841],{"class":35,"line":237},[33,2836,72],{"class":71},[33,2838,76],{"class":75},[33,2840,79],{"class":71},[33,2842,2444],{"class":82},[33,2844,2845,2848,2851],{"class":35,"line":243},[33,2846,2847],{"class":82},"    _count: ",[33,2849,2850],{"class":75},"0",[33,2852,176],{"class":82},[33,2854,2855,2857,2860,2862,2864,2867,2870,2873],{"class":35,"line":251},[33,2856,566],{"class":71},[33,2858,2859],{"class":107}," count",[33,2861,569],{"class":82},[33,2863,572],{"class":71},[33,2865,2866],{"class":71}," ++",[33,2868,2869],{"class":75},"this",[33,2871,2872],{"class":82},"._count; },  ",[33,2874,2875],{"class":39},"\u002F\u002F each access increments!\n",[33,2877,2878],{"class":35,"line":263},[33,2879,2472],{"class":82},[33,2881,2882,2884,2886,2888,2890],{"class":35,"line":290},[33,2883,1877],{"class":75},[33,2885,1869],{"class":82},[33,2887,1882],{"class":107},[33,2889,922],{"class":82},[33,2891,2892],{"class":39},"\u002F\u002F calls count getter → _count becomes 1\n",[33,2894,2895,2897,2899,2901,2903],{"class":35,"line":299},[33,2896,1877],{"class":75},[33,2898,1869],{"class":82},[33,2900,1882],{"class":107},[33,2902,922],{"class":82},[33,2904,2905],{"class":39},"\u002F\u002F calls again → _count becomes 2\n",[33,2907,2908],{"class":35,"line":305},[33,2909,2910],{"class":39},"\u002F\u002F Don't put side effects in getters!\n",[33,2912,2913],{"class":35,"line":310},[33,2914,59],{"emptyLinePlaceholder":58},[33,2916,2917],{"class":35,"line":316},[33,2918,2919],{"class":39},"\u002F\u002F ── `Object.keys` order: integer-like keys first (sorted), then insertion order ──\n",[33,2921,2922,2924,2926,2928,2931,2933,2935,2937,2940,2942,2945,2947,2949,2951,2953,2956],{"class":35,"line":334},[33,2923,72],{"class":71},[33,2925,76],{"class":75},[33,2927,79],{"class":71},[33,2929,2930],{"class":82}," { b: ",[33,2932,278],{"class":75},[33,2934,1405],{"class":82},[33,2936,173],{"class":75},[33,2938,2939],{"class":82},": ",[33,2941,173],{"class":75},[33,2943,2944],{"class":82},", a: ",[33,2946,2271],{"class":75},[33,2948,1405],{"class":82},[33,2950,278],{"class":75},[33,2952,2939],{"class":82},[33,2954,2955],{"class":75},"4",[33,2957,331],{"class":82},[33,2959,2960,2962,2964,2966],{"class":35,"line":358},[33,2961,153],{"class":82},[33,2963,395],{"class":107},[33,2965,922],{"class":82},[33,2967,2968],{"class":39},"\u002F\u002F [\"1\", \"2\", \"b\", \"a\"] — integer keys sorted first, then strings in insertion order\n",[33,2970,2971],{"class":35,"line":386},[33,2972,2973],{"class":39},"\u002F\u002F (ES2020 guarantees this order for for...in, Object.keys, Object.values, Object.entries)\n",[15,2975,2977],{"id":2976},"quick-quiz","🧠 Quick Quiz",[2979,2980,2981,2982,2984,2985,2988],"p",{},"What's the prototype chain of ",[30,2983,803],{},", and what does ",[30,2986,2987],{},"obj.toString()"," return?",[20,2990,2991],{"language":22},[24,2992,2994],{"className":26,"code":2993,"language":22,"meta":28,"style":28},"const obj = Object.create(null);\nobj.x = 1;\nconsole.log(obj.toString());\n",[30,2995,2996,3014,3024],{"__ignoreMap":28},[33,2997,2998,3000,3002,3004,3006,3008,3010,3012],{"class":35,"line":36},[33,2999,72],{"class":71},[33,3001,76],{"class":75},[33,3003,79],{"class":71},[33,3005,716],{"class":82},[33,3007,1035],{"class":107},[33,3009,584],{"class":82},[33,3011,1307],{"class":75},[33,3013,1513],{"class":82},[33,3015,3016,3018,3020,3022],{"class":35,"line":43},[33,3017,89],{"class":82},[33,3019,92],{"class":71},[33,3021,95],{"class":75},[33,3023,98],{"class":82},[33,3025,3026,3028,3030,3033,3036],{"class":35,"line":49},[33,3027,104],{"class":82},[33,3029,108],{"class":107},[33,3031,3032],{"class":82},"(obj.",[33,3034,3035],{"class":107},"toString",[33,3037,3038],{"class":82},"());\n",[3040,3041,3042,3046,3051,3083,3103,3117],"details",{},[3043,3044,3045],"summary",{},"Answer",[2979,3047,3048],{},[30,3049,3050],{},"TypeError: obj.toString is not a function",[2979,3052,3053,3056,3057,3061,3062,3065,3066,3068,3069,3072,3073,1405,3076,1405,3079,3082],{},[30,3054,3055],{},"Object.create(null)"," creates an object with ",[3058,3059,3060],"strong",{},"no prototype"," — its ",[30,3063,3064],{},"[[Prototype]]"," is ",[30,3067,1307],{},". This means it doesn't inherit from ",[30,3070,3071],{},"Object.prototype",", so it has no ",[30,3074,3075],{},"toString()",[30,3077,3078],{},"hasOwnProperty()",[30,3080,3081],{},"constructor",", or any other built-in methods.",[2979,3084,3085,3086,3089,3090,3093,3094,3096,3097,3099,3100,3102],{},"Normal objects (",[30,3087,3088],{},"{}"," or ",[30,3091,3092],{},"new Object()",") have ",[30,3095,3071],{}," as their prototype, which provides ",[30,3098,3075],{},". But ",[30,3101,3055],{}," bypasses this entirely.",[2979,3104,3105,2939,3108,3110,3111,3113,3114,3116],{},[3058,3106,3107],{},"Use case",[30,3109,3055],{}," is useful for creating pure hash maps\u002Fdictionaries where you don't want any inherited properties (no risk of prototype pollution, no ",[30,3112,3081],{}," key, no ",[30,3115,3035],{}," interfering with lookups).",[2979,3118,3119,2939,3122,3124,3125,1405,3127,3130,3131,3133],{},[3058,3120,3121],{},"The lesson",[30,3123,3055],{}," creates objects with no prototype chain — they have zero inherited methods. If you need ",[30,3126,3035],{},[30,3128,3129],{},"hasOwnProperty",", etc., either use ",[30,3132,3088],{}," or add the methods manually.",[3135,3136,3137],"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 .sJ6F3, html code.shiki .sJ6F3{--shiki-default:#032F62;--shiki-github-dark:#9ECBFF}html pre.shiki code .sCrzJ, html code.shiki .sCrzJ{--shiki-default:#E36209;--shiki-github-dark:#FFAB70}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":3139},[3140,3141,3142,3143,3144,3145,3146,3147],{"id":17,"depth":43,"text":18},{"id":691,"depth":43,"text":692},{"id":974,"depth":43,"text":975},{"id":1354,"depth":43,"text":1355},{"id":1660,"depth":43,"text":1661},{"id":2224,"depth":43,"text":2225},{"id":2603,"depth":43,"text":2604},{"id":2976,"depth":43,"text":2977},"Deep-dive into JavaScript object mechanics: property descriptors (writable\u002Fenumerable\u002Fconfigurable), the prototype chain, Object.create vs __proto__, freeze\u002Fseal\u002FpreventExtensions, and hidden class transitions. Code-first reference for senior engineers.","md",{},"\u002Fjs\u002F07-objects-and-properties",{"title":5,"description":3148},"js\u002F07-objects-and-properties","aO24_RHR6EVlNDJP5Hgi3hDbl2-ZNdCwTiDrqkX6gg0",1789924649097]