Arrays are ordered, zero-indexed, mutable collections. JavaScript arrays are not fixed-length and can hold mixed types, though in practice you usually store one type per array. This lesson covers creation, indexing, the mutating and non-mutating methods, destructuring, and the spread operator.
Creating arrays
Use square brackets for a literal. The Array constructor is rarely needed. Array.of builds an array from its arguments and Array.from builds one from an iterable or array-like object, including a mapping function.
const fruits = ["apple", "banana", "cherry"];
const empty = [];
const fromArgs = Array.of(1, 2, 3);
console.log(fromArgs); // [1, 2, 3]
const doubled = Array.from([1, 2, 3], n => n * 2);
console.log(doubled); // [2, 4, 6]
Indexing, length, and at()
Indexing is zero-based. Negative indices with the at() method count from the end. The length property is one more than the last index, so an empty array has length 0 and a one-element array has length 1.
const fruits = ["apple", "banana", "cherry"];
console.log(fruits[0]); // apple
console.log(fruits.at(-1)); // cherry (last element)
console.log(fruits.length); // 3
Mutating methods
push, pop, shift, and unshift add or remove elements at the ends. splice inserts and removes at any position. sort, reverse, and fill modify in place. Prefer non-mutating methods when you do not want to change the original array.
const tasks = ["write", "review"];
tasks.push("deploy");
console.log(tasks); // ['write', 'review', 'deploy']
const last = tasks.pop();
console.log(last, tasks); // deploy ['write', 'review']
tasks.splice(1, 0, "test");
console.log(tasks); // ['write', 'test', 'review']
const nums = [3, 1, 4, 1, 5, 9, 2, 6];
nums.sort((a, b) => a - b);
console.log(nums); // [1, 1, 2, 3, 4, 5, 6, 9]
Non-mutating iterator methods
slice returns a new array (shallow copy). concat joins arrays. includes checks for an element. indexOf finds the first index. join produces a string with a separator. Use these when you want to keep the original intact.
const a = [1, 2, 3];
const b = a.slice(1);
console.log(a, b); // [1, 2, 3] [2, 3]
const c = a.concat([4, 5]);
console.log(c); // [1, 2, 3, 4, 5]
console.log(a.includes(2)); // true
console.log(a.indexOf(2)); // 1
console.log(a.join(" - ")); // 1 - 2 - 3
Destructuring and spread
Array destructuring lets you bind multiple names to elements in one line. The rest pattern collects the remaining elements. The spread operator expands an array in another array or function call.
const rgb = [255, 128, 0];
const [r, g, b] = rgb;
console.log(r, g, b); // 255 128 0
const [first, ...rest] = [1, 2, 3, 4, 5];
console.log(first, rest); // 1 [2, 3, 4, 5]
const a = [1, 2];
const b = [3, 4];
const merged = [...a, ...b, 5];
console.log(merged); // [1, 2, 3, 4, 5]
function max(...nums) {
return nums.reduce((a, b) => a > b ? a : b);
}
console.log(max(1, 5, 3, 9, 2)); // 9
Summary
Arrays are ordered, mutable, zero-indexed. Use at() for negative indices, slice for non-mutating copies, splice for in-place edits, and the iterator methods (map, filter, reduce, find, some, every) to express what you want without manual loops. The next lesson covers objects, Maps, and Sets.
Sorting with care
The default sort converts every element to a string and compares them lexicographically. That works for strings but gives wrong results for numbers. Always pass a comparator: (a, b) => a - b sorts numbers ascending, (a, b) => b - a sorts descending. For objects, sort by the property you care about: (a, b) => a.name.localeCompare(b.name). Arrays of mixed types or non-comparable objects produce implementation-defined results.
const words = ["banana", "Apple", "cherry"];
words.sort(); // ASCII order: Apple, banana, cherry (capital first)
words.sort((a, b) => a.localeCompare(b)); // locale order: Apple, banana, cherry
const users = [{ name: "Asha", age: 28 }, { name: "Bala", age: 31 }];
users.sort((a, b) => a.age - b.age);
console.log(users[0].name); // Asha
flat, flatMap, and modern array features
flat(n) returns a new array with sub-arrays flattened up to depth n (use Infinity for any depth). flatMap maps each element and then flattens one level, which is the right tool for a list-of-lists transform. ES2024 added Array.groupBy and Array.groupByMap for partitioning arrays into a keyed map. These methods do not mutate; they return new arrays.
const nested = [1, [2, 3], [4, [5, 6]]];
console.log(nested.flat(Infinity)); // [1, 2, 3, 4, 5, 6]
const phrases = ["hello world", "foo bar"];
const words = phrases.flatMap(s => s.split(" "));
console.log(words); // ["hello", "world", "foo", "bar"]
const items = [
{ kind: "fruit", name: "apple" },
{ kind: "veg", name: "carrot" },
{ kind: "fruit", name: "banana" },
];
const byKind = Object.fromEntries(
items.groupBy(i => i.kind).entries()
);
console.log(byKind);
Comparison with Python
Python lists play the same role as JavaScript arrays. Both are dynamic, ordered, and support mixed types. Python lists have a richer set of built-in methods like count and index, and Python's list comprehensions often replace map and filter. JavaScript's array iterator methods (map, filter, reduce, find, some, every) match Python's built-in equivalents except for flatMap, which has no Python equivalent without itertools. NumPy arrays are a different beast: they are fixed-shape, fixed-type buffers designed for numerical work, and are far faster than lists for math. JavaScript's TypedArray serves a similar purpose for typed binary data.