JavaScript · Beginner

JavaScript Objects: Properties, Methods and Nesting

10 min readUpdated September 24, 2026Every example verified

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.

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

 JavaScript · 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 error

Use 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?

SituationWrite
Key is a fixed, valid identifierobj.room
Key has spaces or starts with a digitobj["check in"]
Key is stored in a variableobj[field]
Key is computedobj["day" + n]

A room booking as an object

Reading, changing, adding and deleting properties, then listing the keys.

 JavaScript
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' ]
4

booking 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.

 JavaScript
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.

 JavaScript
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
false

Setting 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.field looks for a property literally named field, ignoring the variable, and gives undefined.

    Fix: Use brackets when the key is in a variable: booking[field].

     JavaScript · fix
    const 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 compare JSON.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 this of its own; it uses the this of the surrounding code, which is not your object, so this.balance is undefined and the arithmetic gives NaN.

    Fix: Use the method shorthand deposit(amount) { ... } or a function expression for methods that use this.

     JavaScript · fix
    const account = {
      balance: 10,
      deposit(amount) { this.balance += amount; }
    };
  • Reading a property of something that is undefined

    Why it goes wrong: shop.delivery.radius throws TypeError: Cannot read properties of undefined (reading 'radius') when shop.delivery does not exist; a missing property is undefined, and undefined has no properties.

    Fix: Check the intermediate value first, or use optional chaining shop.delivery?.radius, which yields undefined instead 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.

 JavaScript · in practice
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.key for fixed identifiers, obj[expr] for variables, spaces or computed keys.
  • Assign to add or change a property, delete to remove, in or Object.hasOwn to test.
  • Object.keys, Object.values and Object.entries turn an object into arrays you can loop over.
  • Methods use the shorthand name() {} and reach their object through this; arrows do not get their own this.
  • 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.

Your program
const prices = { loaf: 2.4, roll: 0.6, bagel: 1.1 };
const item = readline();
// print "item: price" or "item: not stocked"
Input the program receives: roll
Expected output: roll: 0.6

Practise this

Open the JavaScript playground

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.

Progress is stored only in this browser.

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.