[{"data":1,"prerenderedAt":1632},["ShallowReactive",2],{"blog-\u002Fblog\u002Fjavascript-objects-properties-descriptors":3},{"id":4,"title":5,"body":6,"description":1617,"difficulty":1618,"extension":1619,"framework":1620,"frameworkSlug":1621,"meta":1622,"navigation":340,"order":68,"path":1623,"qaPath":1624,"seo":1625,"stem":1626,"subtopic":1627,"topic":1628,"topicSlug":1629,"updated":1630,"__hash__":1631},"blog\u002Fblog\u002Fjavascript-objects-properties-descriptors.md","JavaScript Objects & Properties — Creation, Descriptors, Getters and Enumeration",{"type":7,"value":8,"toc":1603},"minimark",[9,14,40,48,52,55,221,247,280,284,295,429,436,440,451,493,500,543,554,627,640,644,659,803,806,810,813,907,935,978,989,993,996,1043,1065,1069,1077,1115,1129,1133,1136,1169,1227,1237,1277,1280,1284,1294,1365,1372,1395,1405,1441,1446,1450,1460,1529,1532,1536,1596,1599],[10,11,13],"h2",{"id":12},"objects-are-the-heart-of-javascript","Objects are the heart of JavaScript",[15,16,17,18,22,23,27,28,31,32,35,36,39],"p",{},"Almost everything in JavaScript that isn't a primitive is an object: arrays, functions,\ndates, regexes, and the plain ",[19,20,21],"code",{},"{}"," you reach for every day. An object is a collection of\n",[24,25,26],"strong",{},"properties",", where each property maps a ",[24,29,30],{},"key"," (a string or a ",[19,33,34],{},"Symbol",") to a\n",[24,37,38],{},"value",". That sounds simple, but the object model has a surprising amount of depth —\ndescriptors, getters, enumeration rules, and immutability controls that most developers\nnever look at directly. Understanding them turns \"objects just work\" into \"I know exactly\nwhy they behave this way,\" which is precisely what interviewers probe for.",[15,41,42,43,47],{},"This guide walks through how objects are created, what a property ",[44,45,46],"em",{},"really"," is under the\nhood, and the tools the language gives you to inspect, protect, and copy them.",[10,49,51],{"id":50},"ways-to-create-an-object","Ways to create an object",[15,53,54],{},"There are several ways to make an object, and each communicates a different intent.",[56,57,62],"pre",{"className":58,"code":59,"language":60,"meta":61,"style":61},"language-js shiki shiki-themes github-light github-dark","const a = {}                       \u002F\u002F object literal — by far the most common\nconst b = new Object()             \u002F\u002F constructor form — almost never used\nconst c = Object.create(proto)     \u002F\u002F create with an explicit prototype\nfunction Point(x) { this.x = x }   \u002F\u002F constructor function\nconst d = new Point(1)\nclass P {}                         \u002F\u002F class\nconst e = new P()\n","js","",[19,63,64,88,111,133,167,189,204],{"__ignoreMap":61},[65,66,69,73,77,80,84],"span",{"class":67,"line":68},"line",1,[65,70,72],{"class":71},"szBVR","const",[65,74,76],{"class":75},"sj4cs"," a",[65,78,79],{"class":71}," =",[65,81,83],{"class":82},"sVt8B"," {}                       ",[65,85,87],{"class":86},"sJ8bj","\u002F\u002F object literal — by far the most common\n",[65,89,91,93,96,98,101,105,108],{"class":67,"line":90},2,[65,92,72],{"class":71},[65,94,95],{"class":75}," b",[65,97,79],{"class":71},[65,99,100],{"class":71}," new",[65,102,104],{"class":103},"sScJk"," Object",[65,106,107],{"class":82},"()             ",[65,109,110],{"class":86},"\u002F\u002F constructor form — almost never used\n",[65,112,114,116,119,121,124,127,130],{"class":67,"line":113},3,[65,115,72],{"class":71},[65,117,118],{"class":75}," c",[65,120,79],{"class":71},[65,122,123],{"class":82}," Object.",[65,125,126],{"class":103},"create",[65,128,129],{"class":82},"(proto)     ",[65,131,132],{"class":86},"\u002F\u002F create with an explicit prototype\n",[65,134,136,139,142,145,149,152,155,158,161,164],{"class":67,"line":135},4,[65,137,138],{"class":71},"function",[65,140,141],{"class":103}," Point",[65,143,144],{"class":82},"(",[65,146,148],{"class":147},"s4XuR","x",[65,150,151],{"class":82},") { ",[65,153,154],{"class":75},"this",[65,156,157],{"class":82},".x ",[65,159,160],{"class":71},"=",[65,162,163],{"class":82}," x }   ",[65,165,166],{"class":86},"\u002F\u002F constructor function\n",[65,168,170,172,175,177,179,181,183,186],{"class":67,"line":169},5,[65,171,72],{"class":71},[65,173,174],{"class":75}," d",[65,176,79],{"class":71},[65,178,100],{"class":71},[65,180,141],{"class":103},[65,182,144],{"class":82},[65,184,185],{"class":75},"1",[65,187,188],{"class":82},")\n",[65,190,192,195,198,201],{"class":67,"line":191},6,[65,193,194],{"class":71},"class",[65,196,197],{"class":103}," P",[65,199,200],{"class":82}," {}                         ",[65,202,203],{"class":86},"\u002F\u002F class\n",[65,205,207,209,212,214,216,218],{"class":67,"line":206},7,[65,208,72],{"class":71},[65,210,211],{"class":75}," e",[65,213,79],{"class":71},[65,215,100],{"class":71},[65,217,197],{"class":103},[65,219,220],{"class":82},"()\n",[15,222,223,224,227,228,230,231,234,235,238,239,242,243,246],{},"The ",[24,225,226],{},"object literal"," ",[19,229,21],{}," is what you'll use 95% of the time. ",[19,232,233],{},"Object.create(proto)"," is\nspecial because it's the only form that lets you set the prototype directly — including\n",[19,236,237],{},"Object.create(null)"," to make a \"bare\" object with ",[24,240,241],{},"no prototype at all",", which is handy\nfor using an object as a clean dictionary with no inherited keys like ",[19,244,245],{},"toString",".",[56,248,250],{"className":58,"code":249,"language":60,"meta":61,"style":61},"const dict = Object.create(null)\ndict.hasOwnProperty   \u002F\u002F undefined — no inherited methods safe as a map\n",[19,251,252,272],{"__ignoreMap":61},[65,253,254,256,259,261,263,265,267,270],{"class":67,"line":68},[65,255,72],{"class":71},[65,257,258],{"class":75}," dict",[65,260,79],{"class":71},[65,262,123],{"class":82},[65,264,126],{"class":103},[65,266,144],{"class":82},[65,268,269],{"class":75},"null",[65,271,188],{"class":82},[65,273,274,277],{"class":67,"line":90},[65,275,276],{"class":82},"dict.hasOwnProperty   ",[65,278,279],{"class":86},"\u002F\u002F undefined — no inherited methods safe as a map\n",[10,281,283],{"id":282},"shorthand-and-computed-keys","Shorthand and computed keys",[15,285,286,287,290,291,294],{},"Modern object literals are expressive. ",[24,288,289],{},"Shorthand properties"," let you omit the value when\na variable matches the key name, and ",[24,292,293],{},"computed keys"," let you build a key from an\nexpression.",[56,296,298],{"className":58,"code":297,"language":60,"meta":61,"style":61},"const name = 'Ada', age = 36\nconst prefix = 'user'\n\nconst user = {\n  name,                       \u002F\u002F shorthand for name: name\n  age,\n  [`${prefix}Id`]: 1,         \u002F\u002F computed key -> userId: 1\n  greet() { return `Hi ${this.name}` }  \u002F\u002F method shorthand\n}\n",[19,299,300,324,336,342,354,362,367,392,423],{"__ignoreMap":61},[65,301,302,304,307,309,313,316,319,321],{"class":67,"line":68},[65,303,72],{"class":71},[65,305,306],{"class":75}," name",[65,308,79],{"class":71},[65,310,312],{"class":311},"sZZnC"," 'Ada'",[65,314,315],{"class":82},", ",[65,317,318],{"class":75},"age",[65,320,79],{"class":71},[65,322,323],{"class":75}," 36\n",[65,325,326,328,331,333],{"class":67,"line":90},[65,327,72],{"class":71},[65,329,330],{"class":75}," prefix",[65,332,79],{"class":71},[65,334,335],{"class":311}," 'user'\n",[65,337,338],{"class":67,"line":113},[65,339,341],{"emptyLinePlaceholder":340},true,"\n",[65,343,344,346,349,351],{"class":67,"line":135},[65,345,72],{"class":71},[65,347,348],{"class":75}," user",[65,350,79],{"class":71},[65,352,353],{"class":82}," {\n",[65,355,356,359],{"class":67,"line":169},[65,357,358],{"class":82},"  name,                       ",[65,360,361],{"class":86},"\u002F\u002F shorthand for name: name\n",[65,363,364],{"class":67,"line":191},[65,365,366],{"class":82},"  age,\n",[65,368,369,372,375,378,381,384,386,389],{"class":67,"line":206},[65,370,371],{"class":82},"  [",[65,373,374],{"class":311},"`${",[65,376,377],{"class":82},"prefix",[65,379,380],{"class":311},"}Id`",[65,382,383],{"class":82},"]: ",[65,385,185],{"class":75},[65,387,388],{"class":82},",         ",[65,390,391],{"class":86},"\u002F\u002F computed key -> userId: 1\n",[65,393,395,398,401,404,407,409,411,414,417,420],{"class":67,"line":394},8,[65,396,397],{"class":103},"  greet",[65,399,400],{"class":82},"() { ",[65,402,403],{"class":71},"return",[65,405,406],{"class":311}," `Hi ${",[65,408,154],{"class":75},[65,410,246],{"class":311},[65,412,413],{"class":82},"name",[65,415,416],{"class":311},"}`",[65,418,419],{"class":82}," }  ",[65,421,422],{"class":86},"\u002F\u002F method shorthand\n",[65,424,426],{"class":67,"line":425},9,[65,427,428],{"class":82},"}\n",[15,430,431,432,435],{},"These reduce noise dramatically compared to the old ",[19,433,434],{},"name: name"," style, and computed keys\nare essential when keys are dynamic.",[10,437,439],{"id":438},"a-property-is-more-than-a-value","A property is more than a value",[15,441,442,443,446,447,450],{},"Here's the part most people miss: each property has not just a value but a set of\n",[24,444,445],{},"attributes"," described by a ",[44,448,449],{},"property descriptor",". For a normal \"data property\" the\ndescriptor has four fields:",[452,453,454,462,470,485],"ul",{},[455,456,457,461],"li",{},[24,458,459],{},[19,460,38],{}," — the stored value.",[455,463,464,469],{},[24,465,466],{},[19,467,468],{},"writable"," — can the value be reassigned?",[455,471,472,477,478,315,481,484],{},[24,473,474],{},[19,475,476],{},"enumerable"," — does it show up in ",[19,479,480],{},"for...in",[19,482,483],{},"Object.keys",", and spreading?",[455,486,487,492],{},[24,488,489],{},[19,490,491],{},"configurable"," — can the property be deleted or its descriptor changed?",[15,494,495,496,499],{},"You can inspect a descriptor with ",[19,497,498],{},"Object.getOwnPropertyDescriptor",":",[56,501,503],{"className":58,"code":502,"language":60,"meta":61,"style":61},"const o = { x: 1 }\nObject.getOwnPropertyDescriptor(o, 'x')\n\u002F\u002F { value: 1, writable: true, enumerable: true, configurable: true }\n",[19,504,505,522,538],{"__ignoreMap":61},[65,506,507,509,512,514,517,519],{"class":67,"line":68},[65,508,72],{"class":71},[65,510,511],{"class":75}," o",[65,513,79],{"class":71},[65,515,516],{"class":82}," { x: ",[65,518,185],{"class":75},[65,520,521],{"class":82}," }\n",[65,523,524,527,530,533,536],{"class":67,"line":90},[65,525,526],{"class":82},"Object.",[65,528,529],{"class":103},"getOwnPropertyDescriptor",[65,531,532],{"class":82},"(o, ",[65,534,535],{"class":311},"'x'",[65,537,188],{"class":82},[65,539,540],{"class":67,"line":113},[65,541,542],{"class":86},"\u002F\u002F { value: 1, writable: true, enumerable: true, configurable: true }\n",[15,544,545,546,549,550,553],{},"Properties created by normal assignment default all three booleans to ",[19,547,548],{},"true",". But\nproperties you define explicitly default them to ",[19,551,552],{},"false"," — a classic gotcha.",[56,555,557],{"className":58,"code":556,"language":60,"meta":61,"style":61},"const obj = {}\nObject.defineProperty(obj, 'hidden', { value: 42 })\nobj.hidden                       \u002F\u002F 42\nObject.keys(obj)                 \u002F\u002F []  not enumerable by default\nobj.hidden = 99                  \u002F\u002F silently fails (writable: false)\n",[19,558,559,571,593,601,614],{"__ignoreMap":61},[65,560,561,563,566,568],{"class":67,"line":68},[65,562,72],{"class":71},[65,564,565],{"class":75}," obj",[65,567,79],{"class":71},[65,569,570],{"class":82}," {}\n",[65,572,573,575,578,581,584,587,590],{"class":67,"line":90},[65,574,526],{"class":82},[65,576,577],{"class":103},"defineProperty",[65,579,580],{"class":82},"(obj, ",[65,582,583],{"class":311},"'hidden'",[65,585,586],{"class":82},", { value: ",[65,588,589],{"class":75},"42",[65,591,592],{"class":82}," })\n",[65,594,595,598],{"class":67,"line":113},[65,596,597],{"class":82},"obj.hidden                       ",[65,599,600],{"class":86},"\u002F\u002F 42\n",[65,602,603,605,608,611],{"class":67,"line":135},[65,604,526],{"class":82},[65,606,607],{"class":103},"keys",[65,609,610],{"class":82},"(obj)                 ",[65,612,613],{"class":86},"\u002F\u002F []  not enumerable by default\n",[65,615,616,619,621,624],{"class":67,"line":169},[65,617,618],{"class":82},"obj.hidden ",[65,620,160],{"class":71},[65,622,623],{"class":75}," 99",[65,625,626],{"class":86},"                  \u002F\u002F silently fails (writable: false)\n",[15,628,629,632,633,636,637,246],{},[19,630,631],{},"Object.defineProperty"," (and ",[19,634,635],{},"Object.defineProperties"," for several at once) is how you\ncreate non-enumerable, read-only, or otherwise specialized properties — the same machinery\nthe language uses internally for things like array ",[19,638,639],{},"length",[10,641,643],{"id":642},"getters-and-setters","Getters and setters",[15,645,646,647,650,651,654,655,658],{},"Instead of a static value, a property can be an ",[24,648,649],{},"accessor"," backed by functions. A\n",[24,652,653],{},"getter"," runs when the property is read; a ",[24,656,657],{},"setter"," runs when it's assigned. They let\na property look like data while running logic.",[56,660,662],{"className":58,"code":661,"language":60,"meta":61,"style":61},"const temp = {\n  celsius: 20,\n  get fahrenheit() { return this.celsius * 9 \u002F 5 + 32 },\n  set fahrenheit(f) { this.celsius = (f - 32) * 5 \u002F 9 }\n}\n\ntemp.fahrenheit        \u002F\u002F 68   — getter runs\ntemp.fahrenheit = 212  \u002F\u002F setter runs\ntemp.celsius           \u002F\u002F 100\n",[19,663,664,675,686,725,766,770,774,782,795],{"__ignoreMap":61},[65,665,666,668,671,673],{"class":67,"line":68},[65,667,72],{"class":71},[65,669,670],{"class":75}," temp",[65,672,79],{"class":71},[65,674,353],{"class":82},[65,676,677,680,683],{"class":67,"line":90},[65,678,679],{"class":82},"  celsius: ",[65,681,682],{"class":75},"20",[65,684,685],{"class":82},",\n",[65,687,688,691,694,696,698,701,704,707,710,713,716,719,722],{"class":67,"line":113},[65,689,690],{"class":71},"  get",[65,692,693],{"class":103}," fahrenheit",[65,695,400],{"class":82},[65,697,403],{"class":71},[65,699,700],{"class":75}," this",[65,702,703],{"class":82},".celsius ",[65,705,706],{"class":71},"*",[65,708,709],{"class":75}," 9",[65,711,712],{"class":71}," \u002F",[65,714,715],{"class":75}," 5",[65,717,718],{"class":71}," +",[65,720,721],{"class":75}," 32",[65,723,724],{"class":82}," },\n",[65,726,727,730,732,734,737,739,741,743,745,748,751,753,756,758,760,762,764],{"class":67,"line":135},[65,728,729],{"class":71},"  set",[65,731,693],{"class":103},[65,733,144],{"class":82},[65,735,736],{"class":147},"f",[65,738,151],{"class":82},[65,740,154],{"class":75},[65,742,703],{"class":82},[65,744,160],{"class":71},[65,746,747],{"class":82}," (f ",[65,749,750],{"class":71},"-",[65,752,721],{"class":75},[65,754,755],{"class":82},") ",[65,757,706],{"class":71},[65,759,715],{"class":75},[65,761,712],{"class":71},[65,763,709],{"class":75},[65,765,521],{"class":82},[65,767,768],{"class":67,"line":169},[65,769,428],{"class":82},[65,771,772],{"class":67,"line":191},[65,773,341],{"emptyLinePlaceholder":340},[65,775,776,779],{"class":67,"line":206},[65,777,778],{"class":82},"temp.fahrenheit        ",[65,780,781],{"class":86},"\u002F\u002F 68   — getter runs\n",[65,783,784,787,789,792],{"class":67,"line":394},[65,785,786],{"class":82},"temp.fahrenheit ",[65,788,160],{"class":71},[65,790,791],{"class":75}," 212",[65,793,794],{"class":86},"  \u002F\u002F setter runs\n",[65,796,797,800],{"class":67,"line":425},[65,798,799],{"class":82},"temp.celsius           ",[65,801,802],{"class":86},"\u002F\u002F 100\n",[15,804,805],{},"Accessors are great for computed\u002Fderived values and validation. The pitfall: an accessor\nthat does heavy work looks like a cheap field but isn't, so callers may read it repeatedly\nwithout realizing the cost. Keep getters fast and side-effect free.",[10,807,809],{"id":808},"enumerating-properties","Enumerating properties",[15,811,812],{},"There are several ways to walk an object's keys, and they differ in what they include.",[56,814,816],{"className":58,"code":815,"language":60,"meta":61,"style":61},"const obj = { a: 1, b: 2 }\n\nObject.keys(obj)      \u002F\u002F ['a', 'b']        own, enumerable, string keys\nObject.values(obj)    \u002F\u002F [1, 2]\nObject.entries(obj)   \u002F\u002F [['a', 1], ['b', 2]]\n\nfor (const key in obj) {}   \u002F\u002F own AND inherited enumerable string keys\n",[19,817,818,839,843,855,868,881,885],{"__ignoreMap":61},[65,819,820,822,824,826,829,831,834,837],{"class":67,"line":68},[65,821,72],{"class":71},[65,823,565],{"class":75},[65,825,79],{"class":71},[65,827,828],{"class":82}," { a: ",[65,830,185],{"class":75},[65,832,833],{"class":82},", b: ",[65,835,836],{"class":75},"2",[65,838,521],{"class":82},[65,840,841],{"class":67,"line":90},[65,842,341],{"emptyLinePlaceholder":340},[65,844,845,847,849,852],{"class":67,"line":113},[65,846,526],{"class":82},[65,848,607],{"class":103},[65,850,851],{"class":82},"(obj)      ",[65,853,854],{"class":86},"\u002F\u002F ['a', 'b']        own, enumerable, string keys\n",[65,856,857,859,862,865],{"class":67,"line":135},[65,858,526],{"class":82},[65,860,861],{"class":103},"values",[65,863,864],{"class":82},"(obj)    ",[65,866,867],{"class":86},"\u002F\u002F [1, 2]\n",[65,869,870,872,875,878],{"class":67,"line":169},[65,871,526],{"class":82},[65,873,874],{"class":103},"entries",[65,876,877],{"class":82},"(obj)   ",[65,879,880],{"class":86},"\u002F\u002F [['a', 1], ['b', 2]]\n",[65,882,883],{"class":67,"line":191},[65,884,341],{"emptyLinePlaceholder":340},[65,886,887,890,893,895,898,901,904],{"class":67,"line":206},[65,888,889],{"class":71},"for",[65,891,892],{"class":82}," (",[65,894,72],{"class":71},[65,896,897],{"class":75}," key",[65,899,900],{"class":71}," in",[65,902,903],{"class":82}," obj) {}   ",[65,905,906],{"class":86},"\u002F\u002F own AND inherited enumerable string keys\n",[15,908,909,910,915,916,919,920,923,924,926,927,930,931,934],{},"The crucial difference: ",[24,911,912,914],{},[19,913,480],{}," walks the prototype chain",", so it can surface\ninherited keys, while ",[19,917,918],{},"Object.keys\u002Fvalues\u002Fentries"," only see the object's ",[44,921,922],{},"own"," enumerable\nproperties. That's why ",[19,925,480],{}," is risky on objects with custom prototypes — guard it\nwith ",[19,928,929],{},"Object.hasOwn(obj, key)"," (or the older ",[19,932,933],{},"obj.hasOwnProperty(key)",").",[56,936,938],{"className":58,"code":937,"language":60,"meta":61,"style":61},"for (const key in obj) {\n  if (Object.hasOwn(obj, key)) { \u002F* only own keys *\u002F }\n}\n",[19,939,940,955,974],{"__ignoreMap":61},[65,941,942,944,946,948,950,952],{"class":67,"line":68},[65,943,889],{"class":71},[65,945,892],{"class":82},[65,947,72],{"class":71},[65,949,897],{"class":75},[65,951,900],{"class":71},[65,953,954],{"class":82}," obj) {\n",[65,956,957,960,963,966,969,972],{"class":67,"line":90},[65,958,959],{"class":71},"  if",[65,961,962],{"class":82}," (Object.",[65,964,965],{"class":103},"hasOwn",[65,967,968],{"class":82},"(obj, key)) { ",[65,970,971],{"class":86},"\u002F* only own keys *\u002F",[65,973,521],{"class":82},[65,975,976],{"class":67,"line":113},[65,977,428],{"class":82},[15,979,980,981,984,985,988],{},"Symbol-keyed and non-enumerable properties are invisible to all of these; use\n",[19,982,983],{},"Object.getOwnPropertySymbols"," or ",[19,986,987],{},"Reflect.ownKeys"," to see everything.",[10,990,992],{"id":991},"checking-for-a-property","Checking for a property",[15,994,995],{},"There are three common membership tests, and they answer subtly different questions.",[56,997,999],{"className":58,"code":998,"language":60,"meta":61,"style":61},"'x' in obj                  \u002F\u002F true if 'x' exists anywhere on the chain\nObject.hasOwn(obj, 'x')     \u002F\u002F true only if it's an OWN property modern\nobj.x !== undefined         \u002F\u002F false negative if the value IS undefined\n",[19,1000,1001,1013,1029],{"__ignoreMap":61},[65,1002,1003,1005,1007,1010],{"class":67,"line":68},[65,1004,535],{"class":311},[65,1006,900],{"class":71},[65,1008,1009],{"class":82}," obj                  ",[65,1011,1012],{"class":86},"\u002F\u002F true if 'x' exists anywhere on the chain\n",[65,1014,1015,1017,1019,1021,1023,1026],{"class":67,"line":90},[65,1016,526],{"class":82},[65,1018,965],{"class":103},[65,1020,580],{"class":82},[65,1022,535],{"class":311},[65,1024,1025],{"class":82},")     ",[65,1027,1028],{"class":86},"\u002F\u002F true only if it's an OWN property modern\n",[65,1030,1031,1034,1037,1040],{"class":67,"line":113},[65,1032,1033],{"class":82},"obj.x ",[65,1035,1036],{"class":71},"!==",[65,1038,1039],{"class":75}," undefined",[65,1041,1042],{"class":86},"         \u002F\u002F false negative if the value IS undefined\n",[15,1044,1045,1048,1049,1052,1053,1056,1057,1060,1061,1064],{},[19,1046,1047],{},"in"," includes inherited properties; ",[19,1050,1051],{},"Object.hasOwn"," (ES2022, the safe replacement for\n",[19,1054,1055],{},"hasOwnProperty",") restricts to own properties. Avoid the ",[19,1058,1059],{},"!== undefined"," check — a property\nthat exists with the value ",[19,1062,1063],{},"undefined"," would be missed.",[10,1066,1068],{"id":1067},"deleting-properties","Deleting properties",[15,1070,223,1071,1074,1075,246],{},[19,1072,1073],{},"delete"," operator removes an own property entirely (descriptor and all), provided it's\n",[19,1076,491],{},[56,1078,1080],{"className":58,"code":1079,"language":60,"meta":61,"style":61},"const o = { a: 1, b: 2 }\ndelete o.a\no            \u002F\u002F { b: 2 }\n",[19,1081,1082,1100,1107],{"__ignoreMap":61},[65,1083,1084,1086,1088,1090,1092,1094,1096,1098],{"class":67,"line":68},[65,1085,72],{"class":71},[65,1087,511],{"class":75},[65,1089,79],{"class":71},[65,1091,828],{"class":82},[65,1093,185],{"class":75},[65,1095,833],{"class":82},[65,1097,836],{"class":75},[65,1099,521],{"class":82},[65,1101,1102,1104],{"class":67,"line":90},[65,1103,1073],{"class":71},[65,1105,1106],{"class":82}," o.a\n",[65,1108,1109,1112],{"class":67,"line":113},[65,1110,1111],{"class":82},"o            ",[65,1113,1114],{"class":86},"\u002F\u002F { b: 2 }\n",[15,1116,1117,1118,1120,1121,984,1123,1125,1126,1128],{},"Don't use ",[19,1119,1073],{}," to \"clear\" a value in performance-sensitive code — it can deoptimize the\nobject's hidden class in some engines. Setting the value to ",[19,1122,269],{},[19,1124,1063],{}," is often\nbetter if you only want to blank it, and reserve ",[19,1127,1073],{}," for genuinely removing a key.",[10,1130,1132],{"id":1131},"freezing-and-sealing-controlling-mutability","Freezing and sealing — controlling mutability",[15,1134,1135],{},"JavaScript gives three levels of lock-down:",[452,1137,1138,1146,1158],{},[455,1139,1140,1145],{},[24,1141,1142],{},[19,1143,1144],{},"Object.preventExtensions(o)"," — no new properties can be added; existing ones stay\nmutable.",[455,1147,1148,1153,1154,1157],{},[24,1149,1150],{},[19,1151,1152],{},"Object.seal(o)"," — prevent extensions ",[44,1155,1156],{},"and"," mark all properties non-configurable\n(can't delete or reconfigure), but values can still change.",[455,1159,1160,1165,1166,1168],{},[24,1161,1162],{},[19,1163,1164],{},"Object.freeze(o)"," — seal ",[44,1167,1156],{}," make every property non-writable: a fully read-only\nobject.",[56,1170,1172],{"className":58,"code":1171,"language":60,"meta":61,"style":61},"const config = Object.freeze({ apiUrl: '\u002Fapi', retries: 3 })\nconfig.retries = 5     \u002F\u002F silently ignored (throws in strict mode)\nObject.isFrozen(config) \u002F\u002F true\n",[19,1173,1174,1202,1214],{"__ignoreMap":61},[65,1175,1176,1178,1181,1183,1185,1188,1191,1194,1197,1200],{"class":67,"line":68},[65,1177,72],{"class":71},[65,1179,1180],{"class":75}," config",[65,1182,79],{"class":71},[65,1184,123],{"class":82},[65,1186,1187],{"class":103},"freeze",[65,1189,1190],{"class":82},"({ apiUrl: ",[65,1192,1193],{"class":311},"'\u002Fapi'",[65,1195,1196],{"class":82},", retries: ",[65,1198,1199],{"class":75},"3",[65,1201,592],{"class":82},[65,1203,1204,1207,1209,1211],{"class":67,"line":90},[65,1205,1206],{"class":82},"config.retries ",[65,1208,160],{"class":71},[65,1210,715],{"class":75},[65,1212,1213],{"class":86},"     \u002F\u002F silently ignored (throws in strict mode)\n",[65,1215,1216,1218,1221,1224],{"class":67,"line":113},[65,1217,526],{"class":82},[65,1219,1220],{"class":103},"isFrozen",[65,1222,1223],{"class":82},"(config) ",[65,1225,1226],{"class":86},"\u002F\u002F true\n",[15,1228,1229,1230,1236],{},"The big caveat: ",[24,1231,1232,1235],{},[19,1233,1234],{},"Object.freeze"," is shallow",". Nested objects are still mutable.",[56,1238,1240],{"className":58,"code":1239,"language":60,"meta":61,"style":61},"const state = Object.freeze({ user: { name: 'Ada' } })\nstate.user.name = 'Grace'   \u002F\u002F still works — nested object not frozen\n",[19,1241,1242,1264],{"__ignoreMap":61},[65,1243,1244,1246,1249,1251,1253,1255,1258,1261],{"class":67,"line":68},[65,1245,72],{"class":71},[65,1247,1248],{"class":75}," state",[65,1250,79],{"class":71},[65,1252,123],{"class":82},[65,1254,1187],{"class":103},[65,1256,1257],{"class":82},"({ user: { name: ",[65,1259,1260],{"class":311},"'Ada'",[65,1262,1263],{"class":82}," } })\n",[65,1265,1266,1269,1271,1274],{"class":67,"line":90},[65,1267,1268],{"class":82},"state.user.name ",[65,1270,160],{"class":71},[65,1272,1273],{"class":311}," 'Grace'",[65,1275,1276],{"class":86},"   \u002F\u002F still works — nested object not frozen\n",[15,1278,1279],{},"For deep immutability you need a recursive freeze helper, or a library. This shallowness\ntrips up people relying on freeze to protect nested config or state.",[10,1281,1283],{"id":1282},"copying-objects","Copying objects",[15,1285,1286,1287,1290,1291,499],{},"Copying is where reference semantics bite. A plain assignment copies the ",[44,1288,1289],{},"reference",", so\nboth variables point at the same object. To get a real copy you spread or use\n",[19,1292,1293],{},"Object.assign",[56,1295,1297],{"className":58,"code":1296,"language":60,"meta":61,"style":61},"const original = { a: 1, nested: { b: 2 } }\n\nconst shallow1 = { ...original }              \u002F\u002F spread — shallow copy\nconst shallow2 = Object.assign({}, original)  \u002F\u002F same effect\n",[19,1298,1299,1320,1324,1345],{"__ignoreMap":61},[65,1300,1301,1303,1306,1308,1310,1312,1315,1317],{"class":67,"line":68},[65,1302,72],{"class":71},[65,1304,1305],{"class":75}," original",[65,1307,79],{"class":71},[65,1309,828],{"class":82},[65,1311,185],{"class":75},[65,1313,1314],{"class":82},", nested: { b: ",[65,1316,836],{"class":75},[65,1318,1319],{"class":82}," } }\n",[65,1321,1322],{"class":67,"line":90},[65,1323,341],{"emptyLinePlaceholder":340},[65,1325,1326,1328,1331,1333,1336,1339,1342],{"class":67,"line":113},[65,1327,72],{"class":71},[65,1329,1330],{"class":75}," shallow1",[65,1332,79],{"class":71},[65,1334,1335],{"class":82}," { ",[65,1337,1338],{"class":71},"...",[65,1340,1341],{"class":82},"original }              ",[65,1343,1344],{"class":86},"\u002F\u002F spread — shallow copy\n",[65,1346,1347,1349,1352,1354,1356,1359,1362],{"class":67,"line":135},[65,1348,72],{"class":71},[65,1350,1351],{"class":75}," shallow2",[65,1353,79],{"class":71},[65,1355,123],{"class":82},[65,1357,1358],{"class":103},"assign",[65,1360,1361],{"class":82},"({}, original)  ",[65,1363,1364],{"class":86},"\u002F\u002F same effect\n",[15,1366,1367,1368,1371],{},"Both produce a ",[24,1369,1370],{},"shallow"," copy: top-level properties are duplicated, but nested objects\nare still shared by reference.",[56,1373,1375],{"className":58,"code":1374,"language":60,"meta":61,"style":61},"shallow1.nested.b = 99\noriginal.nested.b   \u002F\u002F 99  nested object was shared\n",[19,1376,1377,1387],{"__ignoreMap":61},[65,1378,1379,1382,1384],{"class":67,"line":68},[65,1380,1381],{"class":82},"shallow1.nested.b ",[65,1383,160],{"class":71},[65,1385,1386],{"class":75}," 99\n",[65,1388,1389,1392],{"class":67,"line":90},[65,1390,1391],{"class":82},"original.nested.b   ",[65,1393,1394],{"class":86},"\u002F\u002F 99  nested object was shared\n",[15,1396,1397,1398,1401,1402,499],{},"For a true ",[24,1399,1400],{},"deep copy"," of plain data, use the built-in ",[19,1403,1404],{},"structuredClone",[56,1406,1408],{"className":58,"code":1407,"language":60,"meta":61,"style":61},"const deep = structuredClone(original)\ndeep.nested.b = 99\noriginal.nested.b   \u002F\u002F 2  fully independent\n",[19,1409,1410,1425,1434],{"__ignoreMap":61},[65,1411,1412,1414,1417,1419,1422],{"class":67,"line":68},[65,1413,72],{"class":71},[65,1415,1416],{"class":75}," deep",[65,1418,79],{"class":71},[65,1420,1421],{"class":103}," structuredClone",[65,1423,1424],{"class":82},"(original)\n",[65,1426,1427,1430,1432],{"class":67,"line":90},[65,1428,1429],{"class":82},"deep.nested.b ",[65,1431,160],{"class":71},[65,1433,1386],{"class":75},[65,1435,1436,1438],{"class":67,"line":113},[65,1437,1391],{"class":82},[65,1439,1440],{"class":86},"\u002F\u002F 2  fully independent\n",[15,1442,1443,1445],{},[19,1444,1404],{}," handles nested objects, arrays, Maps, Sets, and dates, but it can't clone\nfunctions or DOM nodes. For those rare cases you'll need a custom approach.",[10,1447,1449],{"id":1448},"merging-objects","Merging objects",[15,1451,1452,1453,1455,1456,1459],{},"Spread and ",[19,1454,1293],{}," also merge, with ",[24,1457,1458],{},"later sources winning"," on key conflicts.",[56,1461,1463],{"className":58,"code":1462,"language":60,"meta":61,"style":61},"const defaults = { theme: 'light', size: 'md' }\nconst overrides = { size: 'lg' }\nconst settings = { ...defaults, ...overrides }   \u002F\u002F { theme: 'light', size: 'lg' }\n",[19,1464,1465,1488,1505],{"__ignoreMap":61},[65,1466,1467,1469,1472,1474,1477,1480,1483,1486],{"class":67,"line":68},[65,1468,72],{"class":71},[65,1470,1471],{"class":75}," defaults",[65,1473,79],{"class":71},[65,1475,1476],{"class":82}," { theme: ",[65,1478,1479],{"class":311},"'light'",[65,1481,1482],{"class":82},", size: ",[65,1484,1485],{"class":311},"'md'",[65,1487,521],{"class":82},[65,1489,1490,1492,1495,1497,1500,1503],{"class":67,"line":90},[65,1491,72],{"class":71},[65,1493,1494],{"class":75}," overrides",[65,1496,79],{"class":71},[65,1498,1499],{"class":82}," { size: ",[65,1501,1502],{"class":311},"'lg'",[65,1504,521],{"class":82},[65,1506,1507,1509,1512,1514,1516,1518,1521,1523,1526],{"class":67,"line":113},[65,1508,72],{"class":71},[65,1510,1511],{"class":75}," settings",[65,1513,79],{"class":71},[65,1515,1335],{"class":82},[65,1517,1338],{"class":71},[65,1519,1520],{"class":82},"defaults, ",[65,1522,1338],{"class":71},[65,1524,1525],{"class":82},"overrides }   ",[65,1527,1528],{"class":86},"\u002F\u002F { theme: 'light', size: 'lg' }\n",[15,1530,1531],{},"This \"override order\" is the foundation of options\u002Fconfig patterns. Remember it's a shallow\nmerge — nested objects are replaced wholesale, not deep-merged.",[10,1533,1535],{"id":1534},"key-takeaways","Key takeaways",[452,1537,1538,1552,1560,1563,1573,1588],{},[455,1539,1540,1541,1543,1544,315,1546,315,1548,315,1550,934],{},"Objects map string\u002F",[19,1542,34],{}," keys to values; each property carries a descriptor\n(",[19,1545,38],{},[19,1547,468],{},[19,1549,476],{},[19,1551,491],{},[455,1553,1554,1555,1557,1558,246],{},"Assignment creates fully-enumerable, writable, configurable properties;\n",[19,1556,631],{}," defaults them to ",[19,1559,552],{},[455,1561,1562],{},"Getters\u002Fsetters make accessor properties that run logic but look like data.",[455,1564,1565,1567,1568,1570,1571,246],{},[19,1566,483],{}," and friends see only own enumerable string keys; ",[19,1569,480],{}," also walks the\nprototype chain — guard with ",[19,1572,1051],{},[455,1574,1575,1577,1578,1577,1581,1584,1585,1587],{},[19,1576,1187],{},"\u002F",[19,1579,1580],{},"seal",[19,1582,1583],{},"preventExtensions"," lock objects down, but ",[19,1586,1187],{}," is shallow.",[455,1589,1452,1590,1592,1593,1595],{},[19,1591,1293],{}," make shallow copies\u002Fmerges; reach for ",[19,1594,1404],{}," for\ndeep copies.",[15,1597,1598],{},"Master these and you'll understand not just how to use objects, but why they behave the way\nthey do — the difference between memorizing syntax and genuinely knowing the language.",[1600,1601,1602],"style",{},"html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .s4XuR, html code.shiki .s4XuR{--shiki-default:#E36209;--shiki-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 .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}",{"title":61,"searchDepth":90,"depth":90,"links":1604},[1605,1606,1607,1608,1609,1610,1611,1612,1613,1614,1615,1616],{"id":12,"depth":90,"text":13},{"id":50,"depth":90,"text":51},{"id":282,"depth":90,"text":283},{"id":438,"depth":90,"text":439},{"id":642,"depth":90,"text":643},{"id":808,"depth":90,"text":809},{"id":991,"depth":90,"text":992},{"id":1067,"depth":90,"text":1068},{"id":1131,"depth":90,"text":1132},{"id":1282,"depth":90,"text":1283},{"id":1448,"depth":90,"text":1449},{"id":1534,"depth":90,"text":1535},"A complete guide to JavaScript objects — ways to create them, property descriptors, getters and setters, enumeration, freezing, and copying. Learn how the object model really works.","medium","md","JavaScript","javascript",{},"\u002Fblog\u002Fjavascript-objects-properties-descriptors","\u002Fjavascript\u002Fobjects\u002Fobjects-properties",{"title":5,"description":1617},"blog\u002Fjavascript-objects-properties-descriptors","Objects & Properties","Objects & Prototypes","objects","2026-06-18","ZCATBwqTjdn3g6et5dcAqnN-YyyrEkX_DGhJRfp6Yvc",1781808673080]