A user, a product, an API response: as soon as a piece of data has several named characteristics, it is an object. It is the base structure of the language, to the point where arrays and functions are objects too.
Its syntax takes five minutes to learn. Understanding how it copies takes longer, and explains a large share of shared-data bugs.
Definition
An Object is an unordered collection of key-value pairs. The key is a string, the value can be anything: a number, a string, an array, a function, another object.
const product = { id: 1, title: "Course", price: 49 };
console.log(product.title); // "Course"
console.log(product["price"]); // 49, useful when the key is variable
console.log("price" in product); // true
product.stock = 12; // adds a property
delete product.price; // removes one
console.log(product); // { id: 1, title: "Course", stock: 12 }Dot notation reads better and covers the common case. Brackets become necessary when the key name lives in a variable, or contains a space. The in operator tests for the presence of a key, even when its value is undefined.
The useful static methods
They are called on Object itself rather than on the instance, and turn an object into something you can iterate over.
| Method | Result |
|---|---|
Object.keys(o) | An array of the keys |
Object.values(o) | An array of the values |
Object.entries(o) | An array of [key, value] pairs |
Object.freeze(o) | Blocks any modification |
const product = { title: "Course", price: 49 };
console.log(Object.keys(product)); // ["title", "price"]
console.log(Object.values(product)); // ["Course", 49]
const lines = Object.entries(product).map(([key, value]) => key + " = " + value);
console.log(lines); // ["title = Course", "price = 49"]Object.entries combined with Destructuring and map is the most direct way to walk through an object, since array methods do not apply to one directly.
Object.freeze freezes a single level. In strict mode, which is what modules run in, any write to a frozen object throws instead of being silently ignored.
Copies and references
Like an Array, an object is handled by reference. Two variables can point at the same object, and changing one changes the other.
const base = { price: 49, options: { tax: true } };
const copy = { ...base, price: 59 };
console.log(base.price); // 49, the original is untouched
copy.options.tax = false;
console.log(base.options.tax); // false: the nested object is sharedSpread (...) produces a shallow copy: the first level is duplicated, nested objects stay shared. For a full copy, structuredClone(object) is available in modern browsers and in Node.
Frequently asked questions
How do I loop through an object?
The most readable route is Object.entries, which returns an array you can feed to map or Array.forEach(). The historical for...in loop still exists but also walks inherited properties, which produces surprises on objects built from a class.
When should I prefer a Map over an object?
As soon as the keys are not known ahead of time, are not strings, or insertion order matters. A Map accepts any type of key, exposes a real size and iterates directly. An object stays preferable for a fixed structure whose keys are part of the code.
Why does typeof null return "object"?
It is a flaw present in the very first version of the language, kept ever since so as not to break existing code. To genuinely identify an object you have to check that the value is not null on top of testing typeof. The same caution applies to arrays, which also answer "object".