Skip to main content

Menu

System onlineAI Tutorials / 2026

AI Tutorials
Knowledge search

Recent · Popular · Tutorials

  • dart3 tutorials
  • java1 tutorial
  • Javascript3 tutorials
  • Node.js Introduction2 tutorials
  • dartdart · General · In depth
  • JavascriptJavascript · Advanced · In depth
  • JavascriptJavascript · Advanced · Mid
  • JavascriptJavascript · Advanced · Short

Find a tutorial

Tell the assistant what you want to learn. It suggests published chapters.

For example: “I want to learn Rust ownership from the start.” The conversation is kept only in this tab.

0 / 2,000 characters

Enter to send, Shift+Enter for a new line. Do not include personal information.

Chapter 7

Objects and Properties

This chapter assumes you already know JavaScript's primitive types, how `let`/`const` scoping works, and how functions and `this` behave. Here we focus on the object model itself: how properties are stored, looked up, mutated, and protected, and where the intuitive model ("a bag of key/value pairs")
Level: AdvancedLength: Mid2 min read

Read at another depth

Objects and Properties

This chapter assumes you already know JavaScript's primitive types, how let/const scoping works, and how functions and this behave. Here we focus on the object model itself: how properties are stored, looked up, mutated, and protected, and where the intuitive model ("a bag of key/value pairs") breaks down.

Property Descriptors, Not Just Values

Every property is backed by a property descriptor with value, writable, enumerable, and configurable flags. Assignment syntax (obj.x = 1) creates writable, enumerable, configurable data properties. Object.defineProperty gives fine-grained control:

Code example in javascript
const obj = {};
Object.defineProperty(obj, 'id', {
  value: 42,
  writable: false,
  enumerable: false,
  configurable: false
});
obj.id = 99;                 // silently fails (throws in strict mode)
console.log(Object.keys(obj)); // [] — id is not enumerable

The failure mode to watch for: configurable: false is a one-way door. You cannot later make the property writable or removable. In strict mode or modules, writing to a non-writable property throws a TypeError rather than failing silently.

Accessor Properties

A descriptor may instead have get/set functions. Accessors cost more than plain data properties (the engine can no longer use the fast inline-cache path as cheaply) and can be surprising:

Code example in javascript
const account = {
  get balance() { return this._balance ?? 0; },
  set balance(v) {
    if (typeof v !== 'number') throw new TypeError('number required');
    this._balance = v;
  }
};

Note the trade-off: accessors look like plain fields from the call site, so a future refactor from field to accessor changes evaluation order and cost invisibly.

Internal Methods and Invariants

Property access goes through the internal [[Get]]/[[Set]] operations, which honor the prototype chain and getter semantics. The spec's invariants are why some operations throw: a non-configurable, non-writable property cannot be redefined even via Object.defineProperty, and Object.freeze makes everything non-writable and non-configurable. Shallow-ness is the classic gotcha: Object.freeze(obj) does not freeze nested objects.

Mutation, Identity, and copies

Objects are reference values; assignment copies the reference, never the object. Object.assign and spread create shallow copies only.

Code example in javascript
const a = { nested: { x: 1 } };
const b = { ...a };
b.nested.x = 2;
console.log(a.nested.x); // 2 — same nested object

For deep copies, structuredClone handles cycles and most built-ins, but drops functions (they throw) and rejects some host objects — a deliberate correctness-over-convenience choice.

Exotic Objects and Property Ordering

Integer-like keys are ordered numerically first, then string keys in insertion order, then symbols. Code relying on object key order for logic is fragile; use Map when order matters deliberately.

Proxy objects (covered later) can intercept [[Get]]/[[Set]]; typed arrays are "exotic" with invariants normal objects don't have. When debugging "why did this property lookup behave strangely," check for a Proxy or an accessor on the chain first.

Common errors

  • Spread copies silently sharing nested objects, then mutating through one alias.
  • Assuming Object.freeze is recursive.
  • Using for...in, which walks the prototype chain and includes inherited enumerable properties — prefer Object.keys/Object.entries.
Code example in javascript
for (const k in { a: 1 }) {}        // includes inherited keys
Object.entries({ a: 1 });           // own enumerable string keys only

exercise Q: Why does b.nested.x = 2 in the example above change a? A: Spread copies only the top level; b.nested references the same nested object as a.nested, so mutation through either alias is visible to both.

Spotted a mistake, or code that does not work?

Report an issue

Chapter: Objects and Properties

0 / 2,000 characters

Plain text, for example: the second code sample does not compile. Do not include personal information.

You can't do that