Arrays in JavaScript: From Basics to Common Methods

Indexed JavaScript array with five ordered elements
Indexed JavaScript array with five ordered elements

Arrays in JavaScript are ordered, zero-indexed collections that can hold multiple values under one variable name. They are the standard choice for lists such as tasks, users, messages, and API results. This guide moves from array syntax and indexes to the methods you will use to add, remove, search, transform, copy, and sort data without accidental mutation.

What is an array in JavaScript?

An array is an ordered collection of values. Each value, called an element, has a numbered position called an index. JavaScript starts array indexes at 0, so the first element is at index 0, the second is at index 1, and the last is at array.length - 1.

const tasks = ["plan", "build", "test"]; console.log(tasks[0]); // "plan" console.log(tasks[2]); // "test" console.log(tasks.length); // 3

JavaScript arrays are Array objects. They can grow or shrink and can contain strings, numbers, objects, other arrays, or a mix of types. In production code, an array is usually easier to understand when its elements have a consistent shape.

const temperatures = [18, 21, 19]; const users = [ { id: 1, name: "Ari" }, { id: 2, name: "Mina" }, ]; const matrix = [ [1, 2], [3, 4], ];

Use Array.isArray() when you need to check a value. typeof cannot make this distinction because it returns "object" for arrays.

const temperatures = [18, 21, 19]; console.log(Array.isArray(temperatures)); // true console.log(typeof temperatures); // "object"

The MDN Array reference documents the full set of array properties and methods.

How to create an array

Use an array literal for most lists

An array literal places comma-separated elements inside square brackets. It is the clearest option for an empty array or a known set of values.

const emptyList = []; const colors = ["teal", "navy", "violet"];

Declaring an array with const prevents you from assigning a different array to the same variable. It does not freeze the array. You can still update, add, or remove its elements.

const colors = ["teal", "navy"]; colors.push("violet"); console.log(colors); // ["teal", "navy", "violet"]

Use the Array constructor carefully

The constructor can create arrays, but one numeric argument has a special meaning. It sets the array's length and creates empty slots rather than inserting that number as an element.

const oneNumber = [3]; const threeEmptySlots = new Array(3); console.log(oneNumber.length); // 1 console.log(threeEmptySlots.length); // 3 console.log(0 in threeEmptySlots); // false

This ambiguity is a good reason to prefer array literals. Empty slots also behave differently across some iteration methods, so dense arrays are more predictable.

Build an array from another value

Array.from() converts an iterable or array-like value into an array. Its optional mapping function can create a sequence without empty slots.

const letters = Array.from("array"); const positions = Array.from({ length: 5 }, (_, index) => index + 1); console.log(letters); // ["a", "r", "r", "a", "y"] console.log(positions); // [1, 2, 3, 4, 5]

Access, update, and measure array elements

Read or replace an element with bracket notation. Reading an index that does not exist returns undefined.

const stages = ["draft", "review", "publish"]; console.log(stages[1]); // "review" stages[1] = "edit"; console.log(stages); // ["draft", "edit", "publish"] console.log(stages[10]); // undefined

You can read the last element with length - 1 or at(-1). The at() method is convenient when you want to count from the end.

const stages = ["draft", "review", "publish"]; console.log(stages[stages.length - 1]); // "publish" console.log(stages.at(-1)); // "publish"

For a nested array, use one index for each level.

const grid = [ ["A1", "A2"], ["B1", "B2"], ]; console.log(grid[1][0]); // "B1"

Avoid assigning far beyond the current last index. The following code sets length to 6 and leaves empty slots at indexes 2, 3, and 4.

const stages = ["draft", "review"]; stages[5] = "publish"; console.log(stages.length); // 6 console.log(2 in stages); // false

Add and remove elements

JavaScript provides paired methods for both ends of an array:

OperationMethodReturn value
Add to the endpush()New length
Remove from the endpop()Removed element or undefined
Add to the beginningunshift()New length
Remove from the beginningshift()Removed element or undefined

All four methods change the original array.

const queue = ["email", "review"]; const newLength = queue.push("deploy"); const completed = queue.shift(); console.log(newLength); // 3 console.log(completed); // "email" console.log(queue); // ["review", "deploy"]

Use spread syntax when you need a new array instead of changing the existing one.

const tasks = ["build", "test"]; const withPlan = ["plan", ...tasks]; const withDeploy = [...tasks, "deploy"]; console.log(tasks); // ["build", "test"] console.log(withPlan); // ["plan", "build", "test"] console.log(withDeploy); // ["build", "test", "deploy"]

For the middle of an array, slice() returns a selected section without changing the source. splice() can insert, replace, or remove elements and changes the source. Our guide to slice() and splice() covers their arguments and edge cases in detail.

const steps = ["plan", "build", "test", "deploy"]; const middle = steps.slice(1, 3); console.log(middle); // ["build", "test"] console.log(steps); // ["plan", "build", "test", "deploy"]

Loop through an array

Choose a loop based on what the code needs to do.

Use for...of to read values

for...of is a direct way to process each element. It also supports break, continue, and await inside an async function.

const statuses = ["queued", "running", "complete"]; for (const status of statuses) { console.log(status); }

Use forEach() for a side effect

forEach() calls a function once for each present element. It returns undefined, so it is suitable for logging, updating the UI, or calling another function. Use map() when you need a transformed array.

const statuses = ["queued", "running", "complete"]; statuses.forEach((status, index) => { console.log(`${index}: ${status}`); });

Use a for loop when you need index control

A classic loop is useful when the index drives the logic or when you need to skip by more than one position.

const scores = [82, 91, 76]; for (let index = 0; index < scores.length; index += 1) { console.log(`Score ${index + 1}: ${scores[index]}`); }

Avoid for...in for array elements. It enumerates property names, and custom or inherited enumerable properties can appear alongside numeric indexes.

Search and test array values

Use includes() for a yes-or-no check and indexOf() when you also need the position of a primitive value.

const roles = ["admin", "editor", "viewer"]; console.log(roles.includes("editor")); // true console.log(roles.indexOf("viewer")); // 2 console.log(roles.indexOf("owner")); // -1

For objects or a more specific condition, use find() or findIndex(). The function you pass is a callback. Here it acts as a predicate because it returns a truthy or falsy result.

const users = [ { id: 1, name: "Ari", active: true }, { id: 2, name: "Mina", active: false }, ]; const user = users.find((item) => item.id === 2); const inactiveIndex = users.findIndex((item) => !item.active); console.log(user.name); // "Mina" console.log(inactiveIndex); // 1

some() checks whether at least one element passes a test. every() checks whether all elements pass.

const responseTimes = [120, 185, 240]; console.log(responseTimes.some((time) => time > 200)); // true console.log(responseTimes.every((time) => time < 300)); // true

Transform, filter, and combine array data

Several array methods accept callback functions. The most useful distinction is the shape of the result.

Transform every element with map()

map() returns a new array with one result for each source position. The source array remains unchanged.

const prices = [10, 25, 40]; const pricesWithTax = prices.map((price) => price * 1.08); console.log(pricesWithTax); // [10.8, 27, 43.2] console.log(prices); // [10, 25, 40]

Keep matching elements with filter()

filter() returns a new array containing only elements whose predicate produces a truthy result.

const orders = [ { id: 101, total: 35, status: "paid" }, { id: 102, total: 20, status: "pending" }, { id: 103, total: 50, status: "paid" }, ]; const paidOrders = orders.filter((order) => order.status === "paid"); console.log(paidOrders.length); // 2

Combine elements with reduce()

reduce() carries an accumulator through the array and returns one final value. Supply an initial value so the result is defined for an empty array and the accumulator starts with the type you expect.

const orders = [ { id: 101, total: 35, status: "paid" }, { id: 102, total: 20, status: "pending" }, { id: 103, total: 50, status: "paid" }, ]; const paidRevenue = orders .filter((order) => order.status === "paid") .reduce((sum, order) => sum + order.total, 0); console.log(paidRevenue); // 85

reduce() can build arrays and objects, but that does not make it the best option for every loop. Prefer map() or filter() when their result describes the task more directly.

Copy arrays without sharing the outer array

Assigning an array to another variable creates another reference to the same array.

const original = ["draft", "review"]; const alias = original; alias.push("publish"); console.log(original); // ["draft", "review", "publish"]

Spread syntax, slice(), Array.from(), and concat() can create a new outer array.

const original = ["draft", "review"]; const copy = [...original]; copy.push("publish"); console.log(original); // ["draft", "review"] console.log(copy); // ["draft", "review", "publish"]

These are shallow copies. Nested objects and arrays still share references.

const original = [{ name: "Ari" }]; const copy = [...original]; copy[0].name = "Mina"; console.log(original[0].name); // "Mina"

When nested data must be independent, clone the nested values deliberately. structuredClone() can deep-clone supported structured data, while functions and some host objects need a different strategy.

Sort arrays correctly

sort() converts elements to strings by default. That produces surprising results for many number lists.

const scores = [100, 2, 25]; const defaultOrder = [...scores].sort(); console.log(defaultOrder); // [100, 2, 25]

Pass a comparison function for numeric order. A negative return value places a before b, a positive value places b before a, and zero keeps them equal for sorting purposes.

const scores = [100, 2, 25]; const ascending = [...scores].sort((a, b) => a - b); const descending = [...scores].sort((a, b) => b - a); console.log(ascending); // [2, 25, 100] console.log(descending); // [100, 25, 2]

sort() changes the array it is called on. Copy first, as above, or use toSorted() to return a new sorted array.

const scores = [100, 2, 25]; const ascending = scores.toSorted((a, b) => a - b); console.log(ascending); // [2, 25, 100] console.log(scores); // [100, 2, 25]

See the MDN sort() reference for comparison-function rules and sorting details.

Choose the right array method

Start with the result you need, then choose the method. Mutation matters because a method that changes shared data can affect code far from the call site.

GoalChooseChanges the source?
Run a side effect for each elementforEach()No
Transform every elementmap()No
Keep matching elementsfilter()No
Find one matching elementfind()No
Check whether any element passessome()No
Check whether every element passesevery()No
Combine elements into one resultreduce()No
Add or remove at the endspush(), pop(), shift(), unshift()Yes
Copy a rangeslice()No
Insert, replace, or remove by indexsplice()Yes
Sort in placesort()Yes
Return a sorted copytoSorted()No

Methods that return a new array still copy elements shallowly. If the elements are objects, both arrays can still point to the same objects.

Common JavaScript array mistakes

  1. Treating an index as a position counted from one. The first element is array[0]. An array with length 3 ends at index 2.
  2. Using typeof to detect an array. Use Array.isArray(value).
  3. Assuming assignment copies an array. const copy = original creates a second reference. Use [...original] for a shallow outer copy.
  4. Forgetting return in a block-bodied callback. items.map((item) => { item.id }) produces undefined values. Write items.map((item) => item.id) or add an explicit return.
  5. Sorting numbers without a comparator. Use (a, b) => a - b for ascending numeric order.
  6. Using delete on an array element. delete items[index] leaves an empty slot and does not reduce length. Use splice() to change the original or filter() to build a new array.
  7. Assuming spread creates a deep copy. It only copies the outer array.

Put the methods together

Real code often forms a short pipeline. This example keeps products that are in stock, selects the fields the next step needs, calculates tax, and returns a new price-sorted array.

const products = [ { name: "Desk lamp", price: 45, inStock: true }, { name: "Monitor", price: 220, inStock: false }, { name: "Keyboard", price: 80, inStock: true }, ]; const catalog = products .filter((product) => product.inStock) .map((product) => ({ name: product.name, priceWithTax: Number((product.price * 1.08).toFixed(2)), })) .toSorted((a, b) => a.priceWithTax - b.priceWithTax); console.log(catalog); // [ // { name: "Desk lamp", priceWithTax: 48.6 }, // { name: "Keyboard", priceWithTax: 86.4 } // ]

Each stage has one job, and none changes products. That makes the data flow easier to inspect than a loop that filters, transforms, and sorts through several unrelated mutations.

The core habits are simple: remember zero-based indexes, choose methods by their return value, know which methods mutate, and expect copies to be shallow. Paste the final example into your console, change the input data, and predict each intermediate result before you run it.

Related Posts

We use cookies for functional and analytical purposes. Please refer to our Privacy Policy for details.