Almost all JavaScript data is an array, an object, or some nesting of the two. An array is an ordered list you reach by position; an object is a set of named properties you reach by key. This guide covers both, the methods worth memorising, and the reference behaviour that causes the most confusing bugs beginners hit.
Arrays#
const fruits = ["apple", "pear", "plum"];
console.log(fruits[0]); // apple - counting starts at zero
console.log(fruits.at(-1)); // plum - last item
console.log(fruits.length); // 3
fruits.push("fig"); // add to the end
fruits.pop(); // remove from the end
fruits.unshift("cherry"); // add to the front
fruits.shift(); // remove from the front
Arrays can hold anything, including other arrays and objects, and the types can be mixed:
const mixed = [1, "two", true, null, [3, 4], { name: "Ana" }];
The array methods that matter#
const numbers = [4, 1, 9, 3];
numbers.map(n => n * 2); // [8, 2, 18, 6] - transform
numbers.filter(n => n > 3); // [4, 9] - keep some
numbers.find(n => n > 3); // 4 - first match
numbers.findIndex(n => n > 3); // 0
numbers.includes(9); // true
numbers.some(n => n > 8); // true
numbers.every(n => n > 0); // true
numbers.reduce((sum, n) => sum + n, 0); // 17
numbers.join(", "); // "4, 1, 9, 3"
Some methods change the original array and some return a new one. That distinction causes real bugs:
| Changes the original | Returns a new array |
|---|---|
push, pop, shift, unshift |
map, filter, slice, concat |
sort, reverse, splice |
toSorted, toReversed, with |
const original = [3, 1, 2];
const sorted = original.sort(); // original is now [1, 2, 3] too
const safe = [...original].sort(); // original untouched
const modern = original.toSorted(); // same, newer syntax
Objects#
const person = {
name: "Ana",
age: 34,
greet() {
return "Hello, " + this.name;
},
};
console.log(person.name); // dot notation
console.log(person["age"]); // bracket notation
person.city = "Leeds"; // add
person.age = 35; // update
delete person.city; // remove
console.log("name" in person); // true
console.log(person.email); // undefined - no error
Use brackets when the key is in a variable, or is not a valid identifier:
const field = "age";
console.log(person[field]); // 34
console.log(person["first name"]); // spaces need brackets
Looping#
// Arrays
for (const fruit of fruits) console.log(fruit);
fruits.forEach((fruit, index) => console.log(index, fruit));
for (const [i, fruit] of fruits.entries()) console.log(i, fruit);
// Objects
for (const key of Object.keys(person)) console.log(key);
for (const value of Object.values(person)) console.log(value);
for (const [key, value] of Object.entries(person)) console.log(key, value);
Destructuring#
const [first, second] = fruits;
const [head, ...rest] = fruits;
const { name, age } = person;
const { name: personName } = person; // rename
const { email = "none" } = person; // default for missing
const { address: { city } = {} } = person; // nested, safely
It is used constantly in function parameters:
function describe({ name, age = 0 }) {
return name + " is " + age;
}
describe({ name: "Ana", age: 34 });
The reference trap#
Objects and arrays are handled by reference. Assigning one to a new variable does not copy it:
const a = { count: 1 };
const b = a;
b.count = 99;
console.log(a.count); // 99 - the same object
This is the single most common source of “I changed one thing and something else changed too” bugs. To copy:
const copy = { ...a }; // shallow copy
const arrayCopy = [...fruits];
const merged = { ...defaults, ...userSettings };
But a shallow copy only copies one level. Nested objects are still shared:
const original = { name: "Ana", address: { city: "Leeds" } };
const shallow = { ...original };
shallow.address.city = "York";
console.log(original.address.city); // York - still shared
const deep = structuredClone(original); // fully independent
structuredClone is built into modern browsers and Node, and handles dates, maps and sets correctly — unlike the old JSON.parse(JSON.stringify(x)) trick, which silently destroys them.
Comparing#
console.log({ a: 1 } === { a: 1 }); // false - different objects
console.log([1, 2] === [1, 2]); // false
const x = { a: 1 };
console.log(x === x); // true - same reference
Equality compares references, not contents. To compare contents you have to write the comparison yourself, or compare a serialised form for simple flat data.
Nested data#
const orders = [
{ id: 1, customer: { name: "Ana" }, items: ["book", "pen"] },
{ id: 2, customer: { name: "Sam" }, items: ["lamp"] },
];
const names = orders.map(o => o.customer.name); // ["Ana", "Sam"]
const allItems = orders.flatMap(o => o.items); // 3 items
const total = orders.reduce((n, o) => n + o.items.length, 0);
const byId = Object.fromEntries(orders.map(o => [o.id, o]));
console.log(byId[2].customer.name); // Sam
Optional chaining protects against missing levels:
const city = orders[0]?.customer?.address?.city ?? "unknown";
Questions people ask#
Is an array an object?
Technically yes — typeof [] returns “object”. Use Array.isArray(value) to tell them apart reliably.
When should I use a Map instead of an object?
When keys are not strings, when you add and remove entries frequently, or when insertion order matters and keys might look like numbers. For plain configuration and records, an object is simpler.
Why does typeof null return “object”?
A bug in the first version of JavaScript that was never fixed because too much code depends on it. Check for null explicitly with value === null.
What is the difference between undefined and null?
undefined means the value was never set; null means it was deliberately set to nothing. Both are falsy, and ?? treats them the same.
Where to go next#
- JavaScript array methods reference — every method, with examples.
- Working with the DOM — where these structures meet the page.
- The JavaScript fetch API — the arrays and objects an API returns.