Objects

Lesson 6 of 10

On this page

While arrays group values by position (first, second, third…), objects group values by name. They’re how JavaScript represents “a thing with attributes” — a user with a name and email, a product with a price and SKU, a configuration with a dozen named settings.

Creating and reading objects

You build an object with curly braces, listing key: value pairs separated by commas:

const user = {
    name: "Ada Lovelace",
    role: "admin",
    age: 28,
};

user.name;      // "Ada Lovelace" — dot access, the most common form
user["role"];   // "admin"        — bracket access, for dynamic or unusual keys

Breaking down the syntax:

Use dot access (user.name) whenever you know the property name ahead of time — it’s shorter and easier to read. Reach for bracket access (user["role"]) when the key is stored in a variable or contains characters that aren’t valid in an identifier:

const key = "role";
user[key]; // "admin" — looks up whatever property name `key` holds

Updating and adding properties

Objects created with const can still have their properties changed — only the binding (the variable name pointing to the object) is locked, not the object’s contents:

const user = { name: "Ada", role: "admin" };

user.role = "owner";       // updates an existing property
user.email = "ada@example.com"; // adds a brand new property

console.log(user); // { name: "Ada", role: "owner", email: "ada@example.com" }

Methods — functions stored on an object

A property whose value is a function is called a method. Methods let an object describe behavior alongside its data:

const counter = {
    count: 0,
    increment() {
        this.count += 1;
    },
};

counter.increment();
counter.increment();
console.log(counter.count); // 2

Inside a method, this refers to the object the method was called on — here, counter.

Shorthand syntax you’ll see constantly

When a variable’s name matches the property name you want, you can skip repeating it — and you can define methods without the function keyword:

const name = "Ada";
const role = "admin";

const user = { name, role };       // same as { name: name, role: role }

const counter = {
    count: 0,
    increment() { this.count += 1; }, // shorthand for increment: function () {...}
};

Destructuring — unpacking properties into variables

Just like arrays, objects can be destructured — but by name instead of position, which is the more common form you’ll see:

const user = { name: "Ada", role: "admin", age: 28 };

const { name, role } = user;
console.log(name); // "Ada"
console.log(role); // "admin"

const { name: displayName } = user; // rename while destructuring
console.log(displayName); // "Ada"

Spreading and looping over keys

The spread syntax (...) copies an object’s properties into a new one — handy for making updated copies without changing the original:

const user = { name: "Ada", role: "admin" };
const updated = { ...user, role: "owner" };
// { name: "Ada", role: "owner" } — a new object; `user` is untouched

When you need to inspect all of an object’s properties, Object.keys, Object.values, and Object.entries are the modern way to do it:

const user = { name: "Ada", role: "admin" };

Object.keys(user);   // ["name", "role"]
Object.values(user); // ["Ada", "admin"]
Object.entries(user); // [["name", "Ada"], ["role", "admin"]]

for (const [key, value] of Object.entries(user)) {
    console.log(`${key}: ${value}`);
}

The old way of doing things

Before Object.keys/values/entries were available, looping over an object’s properties meant reaching for for...in:

var user = { name: "Ada", role: "admin" };

for (var key in user) {
    console.log(key + ": " + user[key]);
}

for...in still works, but it has a sharp edge: it also walks up an object’s prototype chain, potentially visiting inherited properties you didn’t intend to include — a frequent source of subtle bugs. Object.keys (and friends) only look at the object’s own properties, which is what you almost always want, so they’ve replaced for...in as the standard approach.

You may also encounter older code building objects with constructor functions and new instead of plain object literals:

function User(name, role) {
    this.name = name;
    this.role = role;
}

var ada = new User("Ada", "admin");

This pattern still appears in legacy code and is the ancestor of modern class syntax, but for grouping simple, related data together, a plain object literal — { name: "Ada", role: "admin" } — remains the simplest and most common choice.