JavaScript · Beginner
JavaScript Objects: Properties, Methods and Nesting
In short: An object is a collection of named values called properties. You create one with a literal { key: value }, read a property with dot or bracket notation, add or change one by assignment, remove one with delete, and store functions in it as methods, which use this to reach the object they belong to.
Grouping related values
Where an array is a list, an object is a record: a set of properties, each with a name (the key) and a value. A booking has a room, a number of guests and a date; putting those three in one object keeps them together and gives each a name, so booking.guests says more than booking[1] ever could. Almost all data a program handles, from a parsed input line to a response from a web service, ends up as objects, arrays of objects, or objects containing arrays.
An object literal lists its properties between braces. Keys are strings (or symbols); when a key is a valid identifier you can write it bare, otherwise quote it. Values can be anything, including arrays, other objects and functions. Two notations read a property. Dot notation, obj.key, is for keys you know when writing the code. Bracket notation, obj["key"] or obj[variable], takes any expression, so it is required for keys with spaces, keys that start with a digit and keys held in variables. Reading a property that does not exist gives undefined, not an error.
Objects are mutable. Assigning to a property changes it or, if it did not exist, adds it. delete obj.key removes one. The in operator asks whether a key exists (including inherited ones); Object.hasOwn(obj, key) (ES2022) asks about the object's own properties only. Object.keys, Object.values and Object.entries return arrays of the keys, the values and the key-value pairs, which is how you loop over an object with for...of. The order is insertion order, except that keys that look like whole numbers come first in ascending order.
A property whose value is a function is called a method, and the shorthand name() { } inside a literal defines one. Inside a method, this refers to the object the method was called on, so account.deposit(50) can read and change account.balance through this.balance. Arrow functions do not have their own this, so they are the wrong tool for methods that need the object. The classes lesson builds on this to define many objects of the same shape.
Objects are held by reference. const same = original gives two names for one object, so a change through either is seen through both, and === compares identity rather than contents. Object.assign({}, obj) and the spread syntax { ...obj } make a shallow copy: a new outer object whose nested objects are still shared. Nested access chains such as shop.address.street throw a TypeError if any link along the way is undefined; the optional chaining operator ?. (ES2020) returns undefined instead.
Syntax
const obj = {
key: value,
"two words": value, // quoted key
nested: { inner: value },
method(arg) { return this.key; } // method shorthand; this is obj
};
obj.key obj["two words"] obj[variableHoldingKey]
obj.key = v; obj.newKey = v; delete obj.key;
"key" in obj Object.hasOwn(obj, "key") // ES2022
Object.keys(obj) Object.values(obj) Object.entries(obj)
obj.nested?.inner // undefined instead of an errorUse dot notation when the key is a fixed identifier; use brackets when the key is in a variable or is not a valid identifier.
Dot or bracket?
| Situation | Write |
|---|---|
| Key is a fixed, valid identifier | obj.room |
| Key has spaces or starts with a digit | obj["check in"] |
| Key is stored in a variable | obj[field] |
| Key is computed | obj["day" + n] |
A room booking as an object
Reading, changing, adding and deleting properties, then listing the keys.
const booking = {
room: "Cedar",
guests: 3,
nights: 2,
"check in": "Friday"
};
console.log(booking.room);
console.log(booking["check in"]);
booking.guests = 4;
booking.breakfast = true;
delete booking.nights;
console.log(booking);
console.log("nights" in booking, "guests" in booking);
console.log(booking.parking);
const field = "room";
console.log(booking[field]);
console.log(Object.keys(booking));
console.log(Object.values(booking).length);Output
Cedar
Friday
{ room: 'Cedar', guests: 4, 'check in': 'Friday', breakfast: true }
false true
undefined
Cedar
[ 'room', 'guests', 'check in', 'breakfast' ]
4booking is declared with const, yet its properties change freely: const fixes the binding, not the contents. guests is overwritten, breakfast is added by plain assignment, and nights is removed by delete, all of which the printed object reflects. "check in" needs quotes and brackets because of the space. Reading the missing parking property gives undefined silently. booking[field] looks up whatever string field holds, which is how a program chooses a property at run time.
Methods, this and nested objects
An account object whose methods change its own state, then a shop with nested address and hours.
const account = {
owner: "Leyla",
balance: 120,
history: [],
deposit(amount) {
this.balance += amount;
this.history.push("+" + amount);
},
withdraw(amount) {
if (amount > this.balance) {
return false;
}
this.balance -= amount;
this.history.push("-" + amount);
return true;
},
summary() {
return this.owner + ": " + this.balance;
}
};
account.deposit(80);
console.log(account.withdraw(500));
console.log(account.withdraw(50));
console.log(account.summary());
console.log(account.history);
const shop = {
name: "Corner Grocer",
address: { street: "Elm Row", number: 14 },
hours: { mon: "8-18", sun: "closed" }
};
console.log(shop.address.street + " " + shop.address.number);
console.log(shop.hours.sun);
console.log(shop.hours.sat);
console.log(shop.delivery?.radius);Output
false true Leyla: 150 [ '+80', '-50' ] Elm Row 14 closed undefined undefined
Inside deposit, this is account, so this.balance += amount updates the object's own property; the balance goes 120, 200, then 150 after the successful withdrawal. The first withdraw is refused because 500 exceeds the balance, and the method reports that by returning false. Nested objects are reached one dot at a time. shop.hours.sat is a missing property on an existing object, so it is undefined; shop.delivery is itself undefined, and without the ?. the attempt to read .radius from it would throw a TypeError.
References, copies and arrays of objects
Two names for one object, a shallow copy, a list of plant records and the entries of an object.
const original = { name: "Tarn", stock: 5 };
const same = original;
same.stock = 0;
console.log(original.stock);
const copy = Object.assign({}, original);
copy.stock = 9;
console.log(original.stock, copy.stock);
const plants = [
{ name: "fern", price: 8 },
{ name: "cactus", price: 5 },
{ name: "ivy", price: 12 }
];
let total = 0;
for (const plant of plants) {
total += plant.price;
}
console.log("Total:", total);
const pricey = plants.filter((p) => p.price >= 8).map((p) => p.name);
console.log(pricey);
console.log(plants[1]);
for (const entry of Object.entries(original)) {
console.log(entry[0] + " = " + entry[1]);
}
console.log({ a: 1 } === { a: 1 });Output
0
0 9
Total: 25
[ 'fern', 'ivy' ]
{ name: 'cactus', price: 5 }
name = Tarn
stock = 0
falseSetting same.stock changes original because both names point at the same object. Object.assign({}, original) builds a new object with the same properties, so changing the copy leaves the original at 0. An array of objects is the most common shape for records: the loop reads plant.price from each, and filter followed by map selects the expensive ones and keeps only their names. Object.entries gives [key, value] pairs, indexed here with [0] and [1]; the destructuring lesson shows a neater way to unpack them. Two literals with identical contents are still two different objects, so === is false.
Common mistakes
Using dot notation with a variable key
Why it goes wrong:
booking.fieldlooks for a property literally namedfield, ignoring the variable, and givesundefined.Fix: Use brackets when the key is in a variable:
booking[field].JavaScript · fixconst field = "room"; console.log(booking[field]);Comparing objects with ===
Why it goes wrong:
===asks whether two references point at the same object, so two separately created objects are never equal even with identical properties.Fix: Compare the properties you care about, e.g.
a.id === b.id, or compareJSON.stringify(a) === JSON.stringify(b)for small plain objects with the same key order.Writing a method as an arrow function
Why it goes wrong: An arrow function has no
thisof its own; it uses thethisof the surrounding code, which is not your object, sothis.balanceisundefinedand the arithmetic givesNaN.Fix: Use the method shorthand
deposit(amount) { ... }or afunctionexpression for methods that usethis.JavaScript · fixconst account = { balance: 10, deposit(amount) { this.balance += amount; } };Reading a property of something that is undefined
Why it goes wrong:
shop.delivery.radiusthrows TypeError: Cannot read properties of undefined (reading 'radius') whenshop.deliverydoes not exist; a missing property isundefined, andundefinedhas no properties.Fix: Check the intermediate value first, or use optional chaining
shop.delivery?.radius, which yieldsundefinedinstead of throwing.
Where you use this
Counting occurrences is the classic small use: an object whose keys are the things being counted and whose values are the counts. Each input word either increments an existing property or creates it, and at the end Object.entries lists the tallies. The same shape serves as a lookup table (a code to its price, a name to its department) that replaces a chain of if statements with a single bracket access. Larger programs model every entity as an object: a user, an order, a sensor reading, usually kept in arrays of objects that filter, map and sort operate on.
const counts = {};
let word;
while ((word = readline()) !== null) {
counts[word] = (counts[word] || 0) + 1;
}
for (const key of Object.keys(counts)) {
console.log(key + ": " + counts[key]);
}Key points
- An object literal
{ key: value }groups named values; keys are strings, values can be anything. obj.keyfor fixed identifiers,obj[expr]for variables, spaces or computed keys.- Assign to add or change a property,
deleteto remove,inorObject.hasOwnto test. Object.keys,Object.valuesandObject.entriesturn an object into arrays you can loop over.- Methods use the shorthand
name() {}and reach their object throughthis; arrows do not get their ownthis. - Objects are references: assignment shares,
===compares identity,Object.assign({}, obj)copies shallowly.
Try it yourself
Read a product name from input. If it is a key of prices, print name: price; otherwise print name: not stocked. Use bracket notation and the in operator.
const prices = { loaf: 2.4, roll: 0.6, bagel: 1.1 };
const item = readline();
// print "item: price" or "item: not stocked"
rollroll: 0.6const prices = { loaf: 2.4, roll: 0.6, bagel: 1.1 };
const item = readline();
if (item in prices) {
console.log(item + ": " + prices[item]);
} else {
console.log(item + ": not stocked");
}
Practise this
- Ticket code countsMedium
Count repeated support codes with a JavaScript object and print a sorted frequency report.
ObjectsNot started
- Warehouse movement tallyMedium
Aggregate warehouse movements by item and print sorted totals with a JavaScript object.
ObjectsNot started
Open the JavaScript playground
Related lessons
- JavaScript Arrays: Creating, Indexing and Changing ListsHow JavaScript arrays store ordered lists: indexing, length, push and pop, slice versus splice, sorting numbers correctly, and map, filter and reduce.10 min
- JavaScript Functions: Declarations, Arrows and Return ValuesHow to define and call JavaScript functions with declarations, expressions and arrow functions; parameters, default values, return and local scope.10 min
- Destructuring in JavaScriptHow JavaScript destructuring unpacks arrays and objects into variables, with defaults, renaming, nested patterns, swaps and function parameters.9 min
- Classes in JavaScriptHow JavaScript classes work: constructors and this, methods on the prototype, getters, static members, extends and super, and private fields with #.11 min
Frequently asked questions
What is the difference between dot and bracket notation?
Dot notation takes a fixed name written into the code: obj.room. Bracket notation takes any expression that evaluates to a key: obj["room"], obj[field], obj["day" + n]. They read the same property when the key is the same; brackets are simply the only option when the key is not a valid identifier or is not known until the program runs.
How do I check whether an object has a property?
"key" in obj is true if the object or anything it inherits from has the key. Object.hasOwn(obj, "key") (ES2022; the older obj.hasOwnProperty("key") is equivalent) is true only for the object's own properties. Testing obj.key !== undefined also works unless a property may legitimately hold undefined.
How do I loop over the properties of an object?
Use for (const key of Object.keys(obj)) for the keys, Object.values(obj) for the values, or Object.entries(obj) for [key, value] pairs. A for...in loop also visits the keys but includes inherited enumerable properties, so the Object.* methods are usually the safer choice.
How this page was checked. Every program on it was run with Node.js 22 at build time; runs in your browser in an isolated Web Worker by the publishing checks, and the output shown is what it printed. The Run buttons execute the same code on your device; nothing you type is sent anywhere.