[{"data":1,"prerenderedAt":170},["ShallowReactive",2],{"qa-\u002Fjavascript\u002Fobjects\u002Fobjects-properties":3},{"page":4,"siblings":154,"blog":167},{"id":5,"title":6,"body":7,"description":11,"difficulty":14,"extension":15,"framework":16,"frameworkSlug":17,"meta":18,"navigation":19,"order":20,"path":21,"questions":22,"related":145,"seo":146,"seoDescription":147,"stem":148,"subtopic":149,"topic":150,"topicSlug":151,"updated":152,"__hash__":153},"qa\u002Fjavascript\u002Fobjects\u002Fobjects-properties.md","Objects Properties",{"type":8,"value":9,"toc":10},"minimark",[],{"title":11,"searchDepth":12,"depth":12,"links":13},"",2,[],"medium","md","JavaScript","javascript",{},true,1,"\u002Fjavascript\u002Fobjects\u002Fobjects-properties",[23,28,32,36,41,45,49,53,57,61,65,69,73,77,81,85,89,93,97,101,105,109,113,117,121,125,129,133,137,141],{"id":24,"difficulty":25,"q":26,"a":27},"create-object","easy","What are the ways to create an object in JavaScript?","Several, each with different use cases:\n\n```js\nconst a = {}                       \u002F\u002F object literal (most common)\nconst b = new Object()             \u002F\u002F constructor (rarely used)\nconst c = Object.create(proto)     \u002F\u002F 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```\n\nThe **object literal** `{}` is by far the most common. `Object.create(proto)`\nis the only one that lets you set the prototype directly (or create a\nprototype-less object with `Object.create(null)`). Constructor functions and\nclasses are for producing many similar objects.\n",{"id":29,"difficulty":25,"q":30,"a":31},"access-properties","What is the difference between dot and bracket notation?","**Dot notation** (`obj.name`) is concise but only works for fixed, valid\nidentifier keys. **Bracket notation** (`obj['name']`) accepts any string or a\ncomputed expression — required for dynamic keys, keys with spaces\u002Fspecial\ncharacters, or numeric-like keys.\n\n```js\nobj.firstName          \u002F\u002F static key\nobj['first-name']      \u002F\u002F key with a hyphen — dot won't work\nconst key = 'age'\nobj[key]               \u002F\u002F dynamic key from a variable\n```\n\nUse dot notation by default; reach for brackets when the key is dynamic or not\na valid identifier.\n",{"id":33,"difficulty":25,"q":34,"a":35},"property-shorthand","What are shorthand properties and computed property names?","**Shorthand** lets you omit the value when a variable has the same name as the\nkey. **Computed names** let you use an expression as a key inside a literal.\n\n```js\nconst name = 'Ada', age = 36\nconst user = { name, age }              \u002F\u002F { name: 'Ada', age: 36 }\n\nconst field = 'email'\nconst obj = { [field]: 'a@b.com', [`is${field}`]: true }\n\u002F\u002F { email: 'a@b.com', isemail: true }\n\nconst methods = { greet() { return 'hi' } } \u002F\u002F method shorthand\n```\n\nThese ES6 features make object construction terser and enable dynamic keys\nwithout a separate assignment.\n",{"id":37,"difficulty":38,"q":39,"a":40},"property-descriptor","hard","What is a property descriptor?","Every property has a **descriptor** describing its attributes. Data properties\nhave `value`, `writable`, `enumerable`, and `configurable`; accessor properties\nhave `get`, `set`, `enumerable`, `configurable`.\n\n```js\nconst obj = {}\nObject.defineProperty(obj, 'id', {\n  value: 1,\n  writable: false,     \u002F\u002F can't reassign\n  enumerable: false,   \u002F\u002F hidden from for...in \u002F Object.keys\n  configurable: false, \u002F\u002F can't delete or redefine\n})\nObject.getOwnPropertyDescriptor(obj, 'id')\n```\n\nProperties created normally default all flags to `true`; `defineProperty`\ndefaults them to `false`. Descriptors let you create read-only or\nnon-enumerable properties — used heavily by the language internals.\n",{"id":42,"difficulty":14,"q":43,"a":44},"getters-setters","What are getters and setters?","Accessor properties that run a function on read (`get`) or write (`set`),\nletting a property be computed or validated while still being accessed like a\nnormal property.\n\n```js\nconst temp = {\n  celsius: 20,\n  get fahrenheit() { return this.celsius * 1.8 + 32 },\n  set fahrenheit(f) { this.celsius = (f - 32) \u002F 1.8 },\n}\ntemp.fahrenheit      \u002F\u002F 68 (computed)\ntemp.fahrenheit = 212\ntemp.celsius         \u002F\u002F 100\n```\n\nThey're useful for derived values, validation, and encapsulation. Define them\nwith `get`\u002F`set` syntax in a literal\u002Fclass, or via `Object.defineProperty`.\n",{"id":46,"difficulty":25,"q":47,"a":48},"object-keys-values-entries","What do Object.keys, Object.values and Object.entries return?","They return arrays of an object's **own enumerable** string-keyed properties:\n\n```js\nconst o = { a: 1, b: 2 }\nObject.keys(o)    \u002F\u002F ['a', 'b']\nObject.values(o)  \u002F\u002F [1, 2]\nObject.entries(o) \u002F\u002F [['a', 1], ['b', 2]]\n\nfor (const [k, v] of Object.entries(o)) console.log(k, v)\n```\n\nThey ignore inherited and non-enumerable properties (and symbol keys). They're\nthe standard way to iterate objects, and `Object.fromEntries` reverses\n`entries` back into an object.\n",{"id":50,"difficulty":14,"q":51,"a":52},"object-assign","What does Object.assign do?","`Object.assign(target, ...sources)` copies **own enumerable** properties from\nthe sources onto the target (a **shallow** copy) and returns the target.\n\n```js\nconst merged = Object.assign({}, defaults, overrides) \u002F\u002F merge into a new object\nconst clone = Object.assign({}, original)             \u002F\u002F shallow clone\n```\n\nIt only copies one level deep — nested objects are shared by reference. The\nspread operator `{ ...a, ...b }` does the same shallow merge more concisely and\nis usually preferred. `Object.assign` also triggers setters on the target.\n",{"id":54,"difficulty":25,"q":55,"a":56},"spread-objects","How does the object spread operator work?","`{ ...obj }` copies an object's own enumerable properties into a new object — a\nconcise shallow copy\u002Fmerge. Later spreads override earlier keys.\n\n```js\nconst updated = { ...user, name: 'Grace' } \u002F\u002F copy + override one field\nconst merged = { ...defaults, ...options }   \u002F\u002F options win on conflicts\n```\n\nLike `Object.assign`, it's **shallow** — nested objects are shared. It's the\nidiomatic way to do immutable updates (especially in React). Spread copies\nvalues, not getters (it evaluates them).\n",{"id":58,"difficulty":14,"q":59,"a":60},"delete-property","How do you remove a property from an object?","The `delete` operator removes a property entirely (so `'key' in obj` becomes\nfalse), returning `true` on success.\n\n```js\nconst obj = { a: 1, b: 2 }\ndelete obj.a\n'a' in obj  \u002F\u002F false\n```\n\nCaveats: `delete` only removes **own** properties (not inherited ones), can't\ndelete `configurable: false` properties, and can deoptimize objects in hot\npaths. For immutable removal, use destructuring: `const { a, ...rest } = obj`.\nSetting to `undefined` keeps the key; `delete` removes it.\n",{"id":62,"difficulty":14,"q":63,"a":64},"check-property-exists","How do you check if a property exists on an object?","Three common approaches, each subtly different:\n\n```js\n'key' in obj                       \u002F\u002F true for own AND inherited properties\nobj.hasOwnProperty('key')          \u002F\u002F own properties only\nObject.hasOwn(obj, 'key')          \u002F\u002F own only (modern, safer)\nobj.key !== undefined              \u002F\u002F fails if the value IS undefined\n```\n\nUse `in` when inherited properties count; use `Object.hasOwn` (ES2022) for own\nproperties — it's safer than `hasOwnProperty`, which can be shadowed or missing\non `Object.create(null)` objects. Checking `=== undefined` is unreliable.\n",{"id":66,"difficulty":38,"q":67,"a":68},"enumerable","What does \"enumerable\" mean for a property?","Enumerable properties show up in `for...in` loops, `Object.keys`, and spread;\nnon-enumerable ones are hidden from them (but still accessible directly).\n\n```js\nconst obj = { visible: 1 }\nObject.defineProperty(obj, 'hidden', { value: 2, enumerable: false })\nObject.keys(obj)             \u002F\u002F ['visible']\nobj.hidden                   \u002F\u002F 2 (still readable)\nObject.getOwnPropertyNames(obj) \u002F\u002F ['visible', 'hidden'] — includes non-enumerable\n```\n\nBuilt-in methods (like array methods on the prototype) are non-enumerable, so\nthey don't appear when you iterate. `getOwnPropertyNames` lists all own\nproperties regardless of enumerability.\n",{"id":70,"difficulty":14,"q":71,"a":72},"for-in","What does for...in iterate over, and what is its pitfall?","`for...in` iterates **enumerable string keys**, including **inherited** ones\nfrom the prototype chain — which is its main pitfall.\n\n```js\nfor (const key in obj) {\n  if (Object.hasOwn(obj, key)) {   \u002F\u002F guard against inherited keys\n    console.log(key, obj[key])\n  }\n}\n```\n\nAlways guard with `Object.hasOwn`\u002F`hasOwnProperty` unless you want inherited\nkeys. For arrays, prefer `for...of` (values) or a normal loop — `for...in`\niterates indices as strings and includes non-index enumerable properties.\n",{"id":74,"difficulty":14,"q":75,"a":76},"object-freeze","What is the difference between Object.freeze, seal and preventExtensions?","Three levels of locking down an object:\n\n- **`preventExtensions`** — can't add new properties; existing ones stay\n  writable\u002Fdeletable.\n- **`seal`** — preventExtensions + can't delete or reconfigure properties; values\n  still writable.\n- **`freeze`** — seal + can't change values. Fully immutable (shallowly).\n\n```js\nconst obj = Object.freeze({ a: 1, nested: { b: 2 } })\nobj.a = 9         \u002F\u002F ignored (throws in strict mode)\nobj.nested.b = 9  \u002F\u002F still works — freeze is SHALLOW\n```\n\nAll three are shallow. Check with `Object.isFrozen`\u002F`isSealed`. For deep\nimmutability, recursively freeze.\n",{"id":78,"difficulty":38,"q":79,"a":80},"shallow-vs-deep-clone","How do you deep clone an object?","Shallow copies (`{ ...obj }`, `Object.assign`) share nested references. For a\nfully independent copy, use **`structuredClone`** (modern, handles cycles,\nDates, Maps), or a library.\n\n```js\nconst deep = structuredClone(original)   \u002F\u002F best built-in option\n\nconst viaJson = JSON.parse(JSON.stringify(original)) \u002F\u002F loses functions,\n\u002F\u002F undefined, Symbols; breaks on Dates\u002FMaps\u002Fcycles\n```\n\n`structuredClone` is the standard now; the `JSON` trick works only for plain\nJSON-safe data and silently mangles everything else.\n",{"id":82,"difficulty":14,"q":83,"a":84},"object-references","Are objects compared by value or reference?","By **reference**. Two distinct objects with identical contents are not equal;\nonly two references to the *same* object are.\n\n```js\n{ a: 1 } === { a: 1 }   \u002F\u002F false (different objects)\nconst x = { a: 1 }\nconst y = x\nx === y                 \u002F\u002F true (same reference)\ny.a = 2; x.a            \u002F\u002F 2 — they share the object\n```\n\nAssigning an object copies the reference, not the object. This underlies\nshallow-copy bugs and why you need `structuredClone` for true independence.\n",{"id":86,"difficulty":25,"q":87,"a":88},"optional-chaining-objects","How does optional chaining help with nested objects?","`?.` short-circuits to `undefined` if a reference is `null`\u002F`undefined`, instead\nof throwing — safe access into deep structures.\n\n```js\nuser?.address?.city           \u002F\u002F undefined if user or address is missing\nuser?.getName?.()             \u002F\u002F call only if it exists\ndata?.items?.[0]              \u002F\u002F safe index access\nconst city = user?.address?.city ?? 'unknown'\n```\n\nIt stops evaluating at the first nullish link. Pair it with `??` for defaults.\nDon't overuse it to mask data that *should* exist — it can hide bugs.\n",{"id":90,"difficulty":14,"q":91,"a":92},"this-in-objects","What does this refer to in an object method?","In a regular-function method called as `obj.method()`, `this` is the object the\nmethod was called on. Extract the method, and `this` is lost.\n\n```js\nconst counter = {\n  count: 0,\n  inc() { this.count++ },\n}\ncounter.inc()              \u002F\u002F this === counter\nconst fn = counter.inc\nfn()                       \u002F\u002F this is undefined -> TypeError\n```\n\nUse method shorthand (a regular function) for methods that need `this`; avoid\narrow methods (their `this` is the outer scope, not the object).\n",{"id":94,"difficulty":38,"q":95,"a":96},"object-create-null","What is Object.create(null) used for?","It creates an object with **no prototype** — a \"pure dictionary\" with no\ninherited properties or methods (`toString`, `hasOwnProperty`, etc.).\n\n```js\nconst dict = Object.create(null)\ndict.key = 'value'\ndict.toString          \u002F\u002F undefined — no Object.prototype\n'toString' in dict     \u002F\u002F false\n```\n\nUseful as a safe map where user-controlled keys won't collide with inherited\nproperty names (e.g. a key literally named `\"hasOwnProperty\"`). The trade-off:\nobject methods aren't available, so use `Object.keys(dict)` etc. (A `Map` is\noften a cleaner choice.)\n",{"id":98,"difficulty":14,"q":99,"a":100},"object-vs-map","When should you use a Map instead of an object?","Use a **`Map`** when keys are dynamic or non-string, when you need ordering and\neasy size, or when you frequently add\u002Fremove entries.\n\n| | Object | Map |\n| --- | --- | --- |\n| Keys | strings\u002Fsymbols | **any type** |\n| Order | mostly insertion (quirky for integer keys) | guaranteed insertion |\n| Size | `Object.keys(o).length` | `map.size` |\n| Iteration | needs `Object.entries` | directly iterable |\n| Prototype keys | risk of collisions | none |\n\nUse a plain **object** for fixed, known-shape records and when you need JSON\nserialization (Maps don't `JSON.stringify` directly).\n",{"id":102,"difficulty":38,"q":103,"a":104},"getownpropertynames","How do you list all properties including non-enumerable and symbols?","`Object.keys` misses non-enumerable and symbol keys. Use the fuller reflection\nmethods:\n\n```js\nObject.getOwnPropertyNames(obj)    \u002F\u002F all string keys (incl. non-enumerable)\nObject.getOwnPropertySymbols(obj)  \u002F\u002F symbol keys\nReflect.ownKeys(obj)               \u002F\u002F EVERYTHING: strings + symbols\n```\n\n`Reflect.ownKeys` is the complete list of own keys. These are needed for deep\ncloning, serialization, and metaprogramming where you must see every property.\n",{"id":106,"difficulty":38,"q":107,"a":108},"property-order","In what order are object keys iterated?","Modern engines follow a spec order: **integer-like keys first, in ascending\nnumeric order**, then **string keys in insertion order**, then **symbol keys in\ninsertion order**.\n\n```js\nconst obj = { b: 1, 2: 1, a: 1, 1: 1 }\nObject.keys(obj) \u002F\u002F ['1', '2', 'b', 'a'] — numbers sorted, then strings as added\n```\n\nSo integer-like keys are *not* in insertion order — a surprise if you rely on\norder. If you need strict insertion order for all keys, use a **`Map`**.\n",{"id":110,"difficulty":25,"q":111,"a":112},"method-vs-property","What is the difference between a method and a property?","A **property** holds a value; a **method** is a property whose value is a\nfunction, so it can be called.\n\n```js\nconst obj = {\n  name: 'Ada',           \u002F\u002F property\n  greet() { return 'hi' }, \u002F\u002F method (function-valued property)\n}\nobj.name      \u002F\u002F 'Ada'\nobj.greet()  \u002F\u002F 'hi'\n```\n\nMethods are just properties that happen to be functions — `typeof obj.greet`\nis `'function'`. Defining a method with shorthand also makes it non-arrow, so\n`this` works correctly.\n",{"id":114,"difficulty":14,"q":115,"a":116},"tostring-override","How do you control how an object converts to a string or number?","Override `toString`\u002F`valueOf`, or implement `Symbol.toPrimitive` for full\ncontrol over coercion.\n\n```js\nconst money = {\n  amount: 100,\n  [Symbol.toPrimitive](hint) {\n    return hint === 'string' ? `$${this.amount}` : this.amount\n  },\n  toString() { return `$${this.amount}` },\n}\n`${money}`   \u002F\u002F '$100'\nmoney + 1    \u002F\u002F 101\n```\n\nWithout these, objects coerce to `[object Object]` (string) via `toString`.\n`Symbol.toPrimitive` takes precedence and receives a hint (`'string'`,\n`'number'`, `'default'`).\n",{"id":118,"difficulty":14,"q":119,"a":120},"json-stringify-object","How does JSON.stringify handle objects?","It serializes **own enumerable** properties, but silently drops `undefined`,\nfunctions, and symbols, converts `NaN`\u002F`Infinity` to `null`, and calls a\n`toJSON()` method if present.\n\n```js\nJSON.stringify({ a: 1, b: undefined, c: () => {}, d: Symbol() })\n\u002F\u002F '{\"a\":1}'  — b, c, d dropped\n\nJSON.stringify(obj, ['a', 'b'])        \u002F\u002F replacer array: only these keys\nJSON.stringify(obj, null, 2)           \u002F\u002F pretty-print with 2-space indent\n```\n\n`BigInt` and circular references **throw**. The optional replacer and space\narguments control filtering and formatting.\n",{"id":122,"difficulty":14,"q":123,"a":124},"chaining-optional-assignment","What does the logical assignment operator ||= and ??= do with objects?","They assign only when the left side is falsy (`||=`) or nullish (`??=`) — handy\nfor defaulting object properties.\n\n```js\nconst config = { timeout: 0 }\nconfig.timeout ||= 1000   \u002F\u002F 1000 overwrites valid 0\nconfig.timeout ??= 1000   \u002F\u002F 0    only fills null\u002Fundefined\nconfig.retries ??= 3      \u002F\u002F adds retries: 3\n```\n\n`??=` is the safe choice when `0`\u002F`''`\u002F`false` are valid values. They're\nshorthand for `x = x ?? value` and short-circuit (the right side isn't\nevaluated if no assignment happens).\n",{"id":126,"difficulty":14,"q":127,"a":128},"object-is","How do you compare two objects for equality?","`===` only checks reference identity, so you must compare contents yourself for\n\"same data\" equality.\n\n```js\nconst shallowEqual = (a, b) => {\n  const ak = Object.keys(a), bk = Object.keys(b)\n  return ak.length === bk.length && ak.every((k) => a[k] === b[k])\n}\n```\n\nFor nested structures you need a recursive **deep equality** (lodash `isEqual`).\nThe `JSON.stringify(a) === JSON.stringify(b)` trick works only for simple data\nand is sensitive to key order and `undefined`.\n",{"id":130,"difficulty":38,"q":131,"a":132},"defineproperties","What is the difference between defining a property and assigning it?","Plain assignment (`obj.x = 1`) creates an enumerable, writable, configurable\ndata property — or **triggers an inherited setter** if one exists.\n`Object.defineProperty` creates the property with explicit (default `false`)\nflags and **bypasses** setters.\n\n```js\nobj.x = 1   \u002F\u002F enumerable: true, writable: true, configurable: true\nObject.defineProperty(obj, 'y', { value: 2 })\n\u002F\u002F enumerable: false, writable: false, configurable: false\n```\n\nUse assignment for normal data; use `defineProperty` for read-only, hidden, or\naccessor properties, or to define multiple at once with `defineProperties`.\n",{"id":134,"difficulty":25,"q":135,"a":136},"nullish-vs-or-default","How do you set default values when destructuring an object?","Provide defaults in the destructuring pattern; they apply only when the value\nis `undefined` (not `null` or other falsy values).\n\n```js\nconst { timeout = 1000, retries = 3, mode = 'auto' } = options\nconst { a: alias = 5 } = obj            \u002F\u002F rename + default\nfunction f({ x = 0, y = 0 } = {}) {}     \u002F\u002F default for the whole object too\n```\n\nThe `= {}` default on the parameter prevents a crash when the argument is\nomitted entirely. Defaults trigger only on `undefined`, so an explicit `null`\noverrides them.\n",{"id":138,"difficulty":14,"q":139,"a":140},"copy-with-rest","How do you copy an object while omitting some properties?","Use destructuring with a **rest** pattern — the named keys are excluded, the\nrest collected into a new object.\n\n```js\nconst { password, ...safe } = user   \u002F\u002F `safe` has everything except password\nconst { [dynamicKey]: _, ...rest } = obj \u002F\u002F omit a dynamic key\n```\n\nThis is the idiomatic immutable \"remove a property\" — it produces a new object\nwithout mutating the original (unlike `delete`). Great for stripping sensitive\nfields before sending data.\n",{"id":142,"difficulty":14,"q":143,"a":144},"object-grouping","How do you transform or group object data?","Convert to entries, transform, and convert back with `Object.fromEntries`:\n\n```js\n\u002F\u002F double every value\nconst doubled = Object.fromEntries(\n  Object.entries(obj).map(([k, v]) => [k, v * 2])\n)\n\u002F\u002F filter keys\nconst filtered = Object.fromEntries(\n  Object.entries(obj).filter(([, v]) => v > 10)\n)\n```\n\n`Object.entries` + array methods + `Object.fromEntries` is the functional\npattern for mapping\u002Ffiltering objects (which have no native `map`\u002F`filter`).\n`Object.groupBy` (ES2024) groups an array into an object by a key function.\n",null,{"description":11},"JavaScript object interview questions — creating objects, property descriptors, getters and setters, Object methods, enumeration, freezing and copying.","javascript\u002Fobjects\u002Fobjects-properties","Objects & Properties","Objects & Prototypes","objects","2026-06-18","8e9eu-hN4JNeXrO12JjJ3sUR5YmuDgSldUUI50UInGc",[155,156,159,163],{"subtopic":149,"path":21,"order":20},{"subtopic":157,"path":158,"order":12},"Prototypes & the Prototype Chain","\u002Fjavascript\u002Fobjects\u002Fprototypes-chain",{"subtopic":160,"path":161,"order":162},"Prototypal Inheritance","\u002Fjavascript\u002Fobjects\u002Fprototypal-inheritance",3,{"subtopic":164,"path":165,"order":166},"The new Operator & Constructors","\u002Fjavascript\u002Fobjects\u002Fnew-constructors",4,{"path":168,"title":169},"\u002Fblog\u002Fjavascript-objects-properties-descriptors","JavaScript Objects & Properties — Creation, Descriptors, Getters and Enumeration",1781808676338]