JavaScript Objects — The Basics
Build a real mental model of JavaScript objects: properties and keys, dot vs bracket access, why objects are shared by reference, iterating with Object.keys/entries, and safe nested access.
Introduction
An object is a collection of labelled values. Where an array is a numbered row of items, an object is a set of named slots: each value is stored under a key (a name) and together a key and its value are called a property. Objects are how you model a *thing* with attributes — a user with a name and an email, a product with a price and a title, a settings record with a dozen options.
Why a second collection type alongside arrays? Because order and naming solve different problems. Reach for an array when you have a *sequence* of similar items and position matters; reach for an object when you have *one thing* described by named fields you'll look up by name. Most real programs are a weave of both: arrays of objects, objects containing arrays.
Two ideas make objects predictable, and this guide is built around them. First, you read and write properties by key, with either dot or bracket notation. Second — exactly like arrays — an object variable holds a reference to the object, not the object itself, which is the source of the most common surprises when copying. Hold those two and the rest is detail.
const user = {
name: 'Ada', // key 'name' → value 'Ada'
age: 36, // key 'age' → value 36
};
Lessons
1. Properties: keys and values
Every entry in an object is a property — a key paired with a value. Keys are strings (or symbols); the values can be anything, including other objects and functions. You create an object with a literal {}, listing the properties you want. This is the foundation: an object *is* its set of properties, and everything else is a way to read, add, or remove them.
const book = {
title: 'Dune',
pages: 412,
inStock: true,
};
2. Reading properties: dot vs bracket
There are two ways to reach a property. Dot notation (user.name) is the everyday choice — short and clear — but it only works when you know the key ahead of time and it's a valid identifier. Bracket notation (user['name']) takes the key as a string, so it works with keys held in a variable, keys with spaces or dashes, and keys computed at runtime. Reading a key that doesn't exist returns undefined rather than throwing.
const user = { name: 'Ada', 'favourite colour': 'teal' };
console.log(user.name); // 'Ada' (dot — known key)
console.log(user['favourite colour']); // 'teal' (bracket — key has a space)
const field = 'name';
console.log(user[field]); // 'Ada' (bracket — key from a variable)
3. Objects are shared by reference
An object variable does not hold the object; it holds a reference to it. Assigning one object variable to another copies the reference, so both names point at the *same* object and a change through one is visible through the other. This is the single biggest source of object bugs: you "copied" a record, edited the copy, and the original changed too.
const original = { count: 1 };
const alias = original; // same object, second name
alias.count = 2;
console.log(original.count); // 2 — changed through 'alias'
console.log(alias === original); // true — one object, two references
To get an independent object, make a copy with the spread operator — { ...original }. Like array spread it is a shallow copy: the top level is new, but any nested objects are still shared. For a fully independent deep copy of plain data, reach for structuredClone(original).
const copy = { ...original };
copy.count = 9;
console.log(original.count); // unchanged by edits to `copy`
4. Adding, removing and checking properties
Objects are mutable: assign to a new key to add a property, use delete to remove one, and test membership with the in operator or Object.hasOwn(). Prefer Object.hasOwn(obj, key) over obj.key !== undefined, because a property can legitimately hold the value undefined, and hasOwn distinguishes "the key exists" from "the value is undefined."
const user = { name: 'Ada' };
user.email = '[email protected]'; // add a property
delete user.name; // remove a property
Object.hasOwn(user, 'email'); // true
5. Iterating over an object
To iterate over an object you first turn its properties into an array, then loop that. Object.keys() gives the keys, Object.values() the values, and Object.entries() the [key, value] pairs — perfect for a for...of loop or a map. These three are the workhorses of object processing, each with its own reference page.
Object.keys(obj)— an array of the object's own keys.Object.entries(obj)— an array of[key, value]pairs, ideal for iterating.Object.values(obj)— an array of just the values.
6. Nested objects and safe access
Real data is nested: an object inside an object inside an array. Reaching deep with plain dot access throws the moment a link in the chain is missing (Cannot read properties of undefined). Optional chaining (?.) short-circuits to undefined instead of throwing, which makes reading uncertain nested data safe. Pair it with the ?? operator to supply a fallback.
const data = { user: { profile: { city: 'Cairo' } } };
data.user?.profile?.city; // 'Cairo'
data.user?.account?.plan; // undefined — no throw
data.user?.account?.plan ?? 'free'; // 'free' (fallback)
That's the whole model. An object is a set of key–value properties; you read them by key with dot or bracket notation; the variable holds a reference, so copy with spread before editing; add, remove and test properties directly; iterate by turning the object into an array of keys, values or entries; and reach into nested data safely with ?.. Every object method beyond these rests on that frame.
Practice
Check your model. After const b = a where a = { n: 1 }, what does b.n = 5 do to a.n? (Answer: it becomes 5 too — a and b are two names for one object.)
Now experiment for real — build a user, copy it with spread, change the copy, and confirm the original survives:
Next steps
You have the mental model — now put it to work. Browse runnable JavaScript object examples for copy-paste snippets, follow how to merge objects for a common task, or read the references for Object.keys() and Object.entries(). If you're comparing collections, see JavaScript arrays — the basics. Every snippet runs in the online JavaScript compiler or the full editor.
Frequently asked questions
What's the difference between dot and bracket notation?
obj.key) is shorter but needs a known, valid-identifier key. Bracket notation (obj['key']) takes the key as a string, so it works with dynamic keys, keys in variables, and keys containing spaces or dashes.Why did changing my copied object also change the original?
= copies the reference, not the object — both names point at the same object. Copy it first with { ...original } (shallow) or structuredClone(original) (deep) before editing.How do I loop over an object's properties?
Object.entries(obj) gives [key, value] pairs for a for...of loop, while Object.keys(obj) and Object.values(obj) give just the keys or values.How do I safely read a deeply nested property?
obj?.a?.b?.c returns undefined instead of throwing if any link is missing. Add ?? fallback to supply a default value.