Objects

From the Data types chapter you know JavaScript has eight built-in types. Seven of them are primitive: a string, a number, a boolean, and so on each hold exactly one value — one indivisible thing.

Objects are the eighth, and they play by different rules. An object is a container for keyed data: a bag of labelled values that can hold as many entries as you like, of any type, including other objects. This one type underpins arrays, dates, errors, DOM nodes, and most of the language’s standard library. Get comfortable with objects early, because you’ll meet them everywhere after this.

You build an object with curly braces {…} and an optional list of properties. Each property is a key: value pair. The key (also called the property name) is a string; the value can be anything at all.

A useful mental picture is a filing cabinet. Every value sits in its own drawer, and the drawer’s label is the key. You look things up by label, and you can add or pull out a drawer whenever you want.

user
keyname‘Maya’
keyage28
An object as a labelled cabinet: each key points to a value in its own drawer.

There are two ways to create an empty object — an empty cabinet:

let user = new Object(); // "object constructor" syntax
let user = {};  // "object literal" syntax

In practice almost everyone reaches for the braces. That form, {...}, is called an object literal.

Literals and properties

You can drop properties straight into the braces as key: value pairs:

let user = {     // an object
  name: "Maya",  // key "name" stores value "Maya"
  age: 28        // key "age" stores value 28
};

The key sits to the left of the colon, the value to the right. The user object above has two properties:

  1. A property named "name" holding the string "Maya".
  2. A property named "age" holding the number 28.

Read a property back with dot notation — the object, a dot, then the key:

// get property values of the object:
alert( user.name ); // Maya
alert( user.age ); // 28

Values can be any type, so let’s add a boolean:

user.isAdmin = true;

That last line does something worth pausing on: user had no isAdmin property, and assigning to it created one. Assignment either updates an existing property or adds a brand-new one.

user (before)
name → ‘Maya’
age → 28
user.isAdmin = true  →
user (after)
name → ‘Maya’
age → 28
isAdmin → true
Assigning to a missing key adds a new drawer to the cabinet.

To throw a property away, use the delete operator:

delete user.age;

Now the age drawer is gone entirely — not set to undefined, but removed from the object.

Try the whole cycle yourself. The buttons below add, update, and delete drawers on a live user object, and the panel redraws after every change:

interactiveAdd, update, and delete properties

Property names can contain spaces or other awkward characters, but then they have to be quoted:

let user = {
  name: "Maya",
  age: 28,
  "likes jazz": true  // a multiword key must be quoted
};

One small syntactic nicety: the last property may be followed by a comma.

let user = {
  name: "Maya",
  age: 28,
}

That’s a trailing (or hanging) comma. It keeps every line looking the same, so reordering or adding properties later touches fewer lines and produces cleaner diffs.

Square brackets

Dot notation has one hard requirement: the key after the dot must be a valid identifier. So a multiword key breaks it:

// this would be a syntax error
user.likes jazz = true

The parser reads user.likes, then hits jazz with no operator between them and gives up. The dot works only when the key contains no spaces, doesn’t start with a digit, and sticks to letters, digits, $, and _.

Square bracket notation has no such limits — it accepts any string:

let user = {};

// set
user["likes jazz"] = true;

// get
alert(user["likes jazz"]); // true

// delete
delete user["likes jazz"];

The key inside the brackets is a quoted string (single or double quotes, either is fine). That’s the escape hatch for keys the dot can’t express.

Brackets do something dot notation can never do: they take the key from an expression evaluated at runtime, not a fixed name baked into your source. For instance, from a variable:

let key = "likes jazz";

// same as user["likes jazz"] = true;
user[key] = true;

Here key could come from a calculation, a config file, or user input — and you use whatever it holds as the property name.

let user = {
  name: "Maya",
  age: 28
};

let key = prompt("What do you want to know about the user?", "name");

// access by variable
alert( user[key] ); // Maya (if the user typed "name")
user.key
key → the literal name “key”
→ undefined
user[key]
key → “name” → property “name”
→ ‘Maya’
Dot uses the name as-written; brackets evaluate the expression first, then use the result as the key.

Type a key name below and watch the two forms diverge. user[key] uses whatever you typed as the property name; user.key always looks for a property literally called key:

interactiveuser.key vs user[key]

Computed properties

The same bracket trick works right inside an object literal, at creation time. That’s a computed property:

let snack = prompt("Which snack to buy?", "chips");

let tray = {
  [snack]: 5, // the property name is taken from the snack variable
};

alert( tray.chips ); // 5 if snack was "chips"

[snack] says: don’t use the text snack as the key — evaluate snack and use its value as the key. If the visitor types "chips", tray becomes {chips: 5}.

It’s the exact equivalent of creating the object first and assigning afterwards, only tidier:

let snack = prompt("Which snack to buy?", "chips");
let tray = {};

// take the property name from the snack variable
tray[snack] = 5;

The expression inside the brackets can be anything, not just a lone variable:

let snack = 'chips';
let tray = {
  [snack + 'Combo']: 5 // tray.chipsCombo = 5
};

So the guidance is simple. Reach for the dot when the key is a fixed, well-formed name — it’s shorter and reads better. Switch to brackets when the key is dynamic or contains characters the dot rejects.

Property value shorthand

You’ll often build objects out of variables that already share the property’s name. A factory function is the classic case:

function makeUser(name, age) {
  return {
    name: name,
    age: age,
    // ...other properties
  };
}

let user = makeUser("Maya", 28);
alert(user.name); // Maya

Writing name: name twice feels repetitive, and it is. Because the pattern is so common, there’s a property value shorthand: when the key and the variable have the same name, write it once.

function makeUser(name, age) {
  return {
    name, // same as name: name
    age,  // same as age: age
    // ...
  };
}

You can freely mix shorthand and full key: value entries in one literal:

let user = {
  name,  // same as name: name
  age: 28
};

Property names limitations

Variable names are restricted: you can’t call one for, let, or return, because those are reserved words. Object property names have no such rule — reserved words are perfectly legal keys:

// all fine
let obj = {
  for: 1,
  let: 2,
  return: 3
};

alert( obj.for + obj.let + obj.return );  // 6

There are effectively no forbidden property names. Keys are strings or symbols (a special identifier type covered later). Hand a key of any other type and JavaScript quietly converts it to a string first.

A number key is the common example — 0 becomes the string "0":

let obj = {
  0: "test" // same as "0": "test"
};

// both read the same property: the number 0 is converted to string "0"
alert( obj["0"] ); // test
alert( obj[0] ); // test (same property)

Property existence test, “in” operator

Objects have a forgiving quality that trips up newcomers from stricter languages: reading a property that doesn’t exist is not an error. You just get undefined back.

let user = {};

alert( user.noSuchProperty === undefined ); // true means "no such property"

So comparing against undefined is one way to check for a property. There’s also a dedicated operator, in:

"key" in object

For example:

let user = { name: "Maya", age: 28 };

alert( "age" in user ); // true, user.age exists
alert( "blabla" in user ); // false, user.blabla doesn't exist

The left side of in is a property name, normally written as a quoted string. Drop the quotes and it becomes a variable whose value is the name to test:

let user = { age: 30 };

let key = "age";
alert( key in user ); // true, property "age" exists

Why bother with in when === undefined usually does the job? Because there’s one case the comparison gets wrong: a property that exists but whose value happens to be undefined.

let obj = {
  test: undefined
};

alert( obj.test ); // undefined — so, no such property?

alert( "test" in obj ); // true — the property really does exist

The === undefined check can’t tell “missing” apart from “present but holding undefined”. The in operator can, because it asks about the key itself, not the value.

key absent
obj.test  → undefined
“test” in obj  → false
key present, value undefined
obj.test  → undefined
“test” in obj  → true
Two things that both read as undefined via dot access — only `in` distinguishes them.

See the distinction directly. The object below starts empty; the buttons add keys — including one whose value is undefined. Only in can tell that last one apart from a key that was never added:

interactive=== undefined vs the in operator

In day-to-day code this rarely bites, because you shouldn’t assign undefined on purpose — reach for null when you mean “empty” or “unknown”. That’s why in stays a somewhat rare sight.

The “for..in” loop

To visit every key in an object, JavaScript has a dedicated loop: for..in. Despite the shared keyword, it’s a different construct from the for(;;) counting loop you saw earlier.

for (key in object) {
  // runs the body once per key in the object
}

Let’s list everything in user:

let user = {
  name: "Maya",
  age: 28,
  isAdmin: true
};

for (let key in user) {
  // keys
  alert( key );  // name, age, isAdmin
  // values by key
  alert( user[key] ); // Maya, 28, true
}

As with every for variant, you can declare the loop variable inline with let key. The name key isn’t special — for (let prop in user) reads just as well, and plenty of people write it that way.

key = ‘name’‘Maya’
key = ‘age’28
key = ‘isAdmin’true
Each pass binds the loop variable to the next key; user[key] reads that key's value.

Ordered like an object

Do the keys come out in the order you added them? The honest answer is “mostly, with one rule you need to know.” Integer-like keys get sorted numerically; everything else keeps insertion order.

Watch it bite with a table of phone codes:

let codes = {
  "91": "India",
  "81": "Japan",
  "61": "Australia",
  // ..,
  "7": "Russia"
};

for (let code in codes) {
  alert(code); // 7, 61, 81, 91
}

Say you’re building a site for an Indian audience and want 91 listed first. Run this and you get the opposite: 7 leads, then 61, 81, 91. The keys look like integers, so the engine sorts them in ascending numeric order and ignores the order you wrote them in.

Non-integer keys, by contrast, always come out in creation order:

let user = {
  name: "Maya",
  surname: "Vance"
};
user.age = 34; // add one more

// non-integer properties keep insertion order
for (let prop in user) {
  alert( prop ); // name, surname, age
}

That gives you a clean fix for the phone codes: make the keys non-integer so they escape the numeric sort. Prefixing each with a "+" does it — those strings no longer round-trip as integers.

let codes = {
  "+91": "India",
  "+81": "Japan",
  "+61": "Australia",
  // ..,
  "+7": "Russia"
};

for (let code in codes) {
  alert( +code ); // 91, 81, 61, 7
}

Now the loop yields them in the order you wrote, and +code strips the plus back off when you need the number.

keys “91”,“81”,“61”,“7”
sorted → 7, 61, 81, 91
keys “+91”,“+81”,“+61”,“+7”
insertion order → +91, +81, +61, +7
Integer-like keys are sorted numerically; every other key keeps the order it was added.

Toggle the prefix below and re-run the loop. With plain digit keys the engine sorts them numerically; add a "+" and every key becomes non-integer, so for..in hands them back in the exact order they were written:

interactivefor..in ordering: integer keys vs prefixed keys

Summary

Objects are associative arrays with a handful of special behaviors on top.

They hold properties — key/value pairs — where:

  • Keys are strings or symbols (usually strings). Other types get coerced to strings.
  • Values can be any type.

To read or write a property:

  • Dot notation: obj.property, for fixed, identifier-friendly names.
  • Bracket notation: obj["property"], which also takes the key from an expression — obj[varWithKey].

The extra operators worth remembering:

  • Remove a property: delete obj.prop.
  • Test for a key: "key" in obj.
  • Walk every key: for (let key in obj).

What you’ve met here is a plain object, or just Object. JavaScript ships many other object flavors built on the same foundation:

  • Array for ordered collections,
  • Date for dates and times,
  • Error for error information,
  • and plenty more.

People sometimes say “Array type” or “Date type,” but formally these aren’t separate types — they’re all the single object type, extended in different directions. This chapter only opened the door; objects run deep, and you’ll keep learning more about them throughout the course.