JavaScript Array Explained: Create, Access, Loop and Reshape

A JavaScript array holds an ordered list of values under a single variable. Unlike arrays in languages such as Java or C, a JS array can store a number, a string, a boolean and an object all in the same list with no fixed size or fixed type. That flexibility makes arrays one of the most-used data structures in JavaScript. This article covers how to create, access, modify and work with arrays, including the array methods you reach for most often.

Array in other programming languages

In most languages, an array is typed. Once you declare an array of integers, it can only store integers. JavaScript treats arrays as objects, so they can hold any mix of values. That distinction matters because it changes how you design data structures. A shopping cart item, say, can sit alongside a numeric price and a boolean inStock flag inside the same array.

Structure of an array

An array contains elements inside square brackets, separated by commas:

["element1", "element2", "element3"];

Each element has a numeric index starting at 0. The first element is at index 0, the second at index 1, and so on.

How to create a JavaScript array

Using array literals

The preferred way is to assign square brackets directly to a variable:

const fruits = ["apple", "banana", "mango"];
const empty = [];

Literals are shorter, faster to parse and less likely to surprise you.

Using the Array constructor

You can also call the built-in Array class:

const arr = new Array("apple", "banana", "mango");

There is one trap here worth knowing about. When you pass a single number to new Array(), it creates that many empty slots rather than creating an array with that number as an element:

const a = [4];          // [ 4 ] - one element, the number 4
const b = new Array(4); // [ <4 empty items> ] - four empty slots

Stick to literals unless you have a clear reason to use the constructor.

Creating an array from a string

Use split() to turn a delimited string into an array, or Array.from() to convert any iterable:

const csv = "red,green,blue";
const colors = csv.split(",");
// ["red", "green", "blue"]

const chars = Array.from("hello");
// ["h", "e", "l", "l", "o"]

Accessing array elements

Access an element by placing its index inside square brackets:

const arr = ["element1", "element2", "element3"];
console.log(arr[0]); // "element1"
console.log(arr[2]); // "element3"

The last element is always at arr[arr.length - 1]. ES2022 added at(), which also accepts negative integers to count from the end:

const fruits = ["apple", "banana", "mango"];
console.log(fruits.at(-1)); // "mango" - last element
console.log(fruits.at(-2)); // "banana"

at() is cleaner than writing arr[arr.length - 1] every time.

Assigning and changing array elements

Assign to any index position to add or overwrite a value:

const arr = ["element1", "element2", "element3"];

// Add a fourth element
arr[3] = "element4";

// Change the first element
arr[0] = "new element";

console.log(arr);
// ["new element", "element2", "element3", "element4"]

Watch out: if you skip an index, JavaScript creates empty slots between the last populated index and the one you wrote to. Those slots read as undefined and cause odd behavior in some array methods.

const arr = ["a", "b"];
arr[5] = "f";
// ["a", "b", <3 empty slots>, "f"]

Use push() instead to avoid gaps.

Adding elements to an array

push: add to the end

push() appends one or more elements to the end and returns the new length:

const arr = ["element1", "element2"];
arr.push("element3");
console.log(arr); // ["element1", "element2", "element3"]

unshift: add to the beginning

unshift() prepends elements and also returns the new length:

const arr = ["element2", "element3"];
arr.unshift("element1");
console.log(arr); // ["element1", "element2", "element3"]

splice: insert at any position

splice(startIndex, deleteCount, ...itemsToInsert) is the multi-tool for adding, removing and replacing at any position:

const countries = ["Ghana", "Nigeria", "Rwanda"];
// Insert "Kenya" at index 1, delete 0 elements
countries.splice(1, 0, "Kenya");
console.log(countries); // ["Ghana", "Kenya", "Nigeria", "Rwanda"]

concat: merge without mutating

concat() joins two or more arrays into a new array, leaving the originals untouched:

const a = ["HTML", "CSS"];
const b = ["JS", "Node"];
const full = a.concat(b);
console.log(full); // ["HTML", "CSS", "JS", "Node"]

Removing array elements

pop: remove the last element

const arr = ["element1", "element2", "element3"];
const removed = arr.pop();
console.log(removed); // "element3"
console.log(arr);     // ["element1", "element2"]

shift: remove the first element

const arr = ["element1", "element2", "element3"];
const removed = arr.shift();
console.log(removed); // "element1"
console.log(arr);     // ["element2", "element3"]

splice: remove from any position

Pass a start index and delete count:

const arr = ["a", "b", "c", "d"];
const removed = arr.splice(1, 2); // remove 2 elements starting at index 1
console.log(removed); // ["b", "c"]
console.log(arr);     // ["a", "d"]

Length of an array

The length property tells you how many elements are in the array. Unlike index numbers, it counts from 1:

const arr = ["element1", "element2", "element3"];
console.log(arr.length); // 3

You can also set length directly to grow or shrink the array:

arr.length = 5;  // adds 2 empty slots
arr.length = 1;  // keeps only the first element

Looping through array elements

Classic for loop

const arr = ["element1", "element2", "element3"];
for (let i = 0; i < arr.length; i++) {
    console.log(arr[i]);
}

for…of loop

Cleaner when you only need the values:

for (const item of arr) {
    console.log(item);
}

forEach

The forEach method runs a callback once per element. It never returns a new array, so use it for side effects like logging or updating the DOM:

arr.forEach((item, index) => {
    console.log(index, item);
});

Arrays are objects

The typeof operator returns "object" for arrays. To reliably check whether a value is an array, use Array.isArray():

const arr = ["element1", "element2"];

typeof arr;          // "object"
Array.isArray(arr);  // true

// The instanceof operator also works
arr instanceof Array; // true

Array.isArray() is the safest choice because instanceof can fail across different execution contexts (such as iframes).

Arrays vs objects

Both arrays and objects store multiple values, but they differ in how you access them. Arrays use numeric indexes. Objects use named keys (strings or symbols). Use an array when order matters and you want to iterate by position. Use an object when you want to look up values by name.

// Array — indexed access
const person = ["John", "Doe", 46];
console.log(person[0]); // "John"

// Object — named access
const profile = { firstName: "John", lastName: "Doe", age: 46 };
console.log(profile.firstName); // "John"

JavaScript does not support associative arrays (named indexes on an array). If you use a string as an array index, JavaScript silently converts the array to a plain object, which breaks length and most array methods.

Nested arrays (multidimensional arrays)

An array element can itself be an array. This is how you create grids, matrices and structured datasets:

const matrix = [
    [1, 2, 3],
    [4, 5, 6],
    [7, 8, 9]
];

console.log(matrix[1][2]); // 6 — row 1, column 2

To loop through nested arrays, nest two loops:

for (const row of matrix) {
    for (const cell of row) {
        console.log(cell);
    }
}

You can also use flat() to collapse nested arrays into a single level:

const nested = [1, [2, 3], [4, [5, 6]]];
console.log(nested.flat());    // [1, 2, 3, 4, [5, 6]]
console.log(nested.flat(2));   // [1, 2, 3, 4, 5, 6]

Copying arrays: shallow vs deep

Assigning an array to a new variable does not copy it. Both variables point to the same array in memory. Changing one changes the other:

const a = [1, 2, 3];
const b = a;       // b is just another name for a
b.push(4);
console.log(a);    // [1, 2, 3, 4] — a changed too

For a shallow copy (elements are copied by reference if they are objects), use the spread operator, Array.from() or slice():

const original = [1, 2, 3];
const copy1 = [...original];
const copy2 = Array.from(original);
const copy3 = original.slice();

For a deep copy of nested arrays or arrays of objects, use structuredClone() (available natively in modern environments):

const nested = [[1, 2], [3, 4]];
const deep = structuredClone(nested);
deep[0].push(99);
console.log(nested[0]); // [1, 2] — untouched

JSON.parse(JSON.stringify(arr)) is the older fallback for JSON.stringify-compatible data, but structuredClone handles more data types and is cleaner.

Array destructuring and spread

Array destructuring lets you pull elements into named variables in one line:

const [first, second, ...rest] = ["a", "b", "c", "d"];
console.log(first);  // "a"
console.log(second); // "b"
console.log(rest);   // ["c", "d"]

The spread operator (...) expands an array into individual elements. Useful for merging arrays or passing elements as function arguments:

const a = [1, 2, 3];
const b = [4, 5, 6];
const merged = [...a, ...b]; // [1, 2, 3, 4, 5, 6]

Math.max(...a); // 3

Essential array methods

This is where arrays become genuinely powerful. All the methods below return a new array (or a value) without mutating the original unless stated.

map: apply a function to every element

map() applies a function to each element and returns a new array of the same length. The original is never changed.

const prices = [10, 20, 30];
const withTax = prices.map(p => p * 1.18);
console.log(withTax); // [11.8, 23.6, 35.4]

filter: keep only matching elements

filter() returns a new array containing only elements for which the callback returns true:

const scores = [45, 72, 88, 33, 91];
const passing = scores.filter(s => s >= 50);
console.log(passing); // [72, 88, 91]

reduce: combine to a single value

reduce() runs a reducer function across all elements to produce a single output: a sum, an object or a string:

const numbers = [1, 2, 3, 4, 5];
const sum = numbers.reduce((acc, curr) => acc + curr, 0);
console.log(sum); // 15

You can chain filter, map and reduce together. Filter first to narrow the data, map to reshape it, reduce to aggregate it. This pattern shows up often in dashboards and data visualizations that rely on setInterval to refresh arrays of values.

find and findIndex

find() returns the first element that matches a condition. findIndex() returns its position:

const users = [
    { id: 1, name: "Alice" },
    { id: 2, name: "Bob" }
];

const user = users.find(u => u.id === 2);
// { id: 2, name: "Bob" }

const pos = users.findIndex(u => u.id === 2);
// 1

includes: check for a value

const arr = ["a", "b", "c"];
arr.includes("b"); // true
arr.includes("z"); // false

indexOf: find an element’s position

indexOf() searches left to right and returns the first matching index, or -1 if not found:

const arr = ["a", "b", "c", "b"];
arr.indexOf("b"); // 1
arr.indexOf("z"); // -1

sort and reverse

sort() sorts in place. Without a comparator, it converts elements to strings, which gives wrong results for numbers:

const nums = [10, 9, 2, 21, 3];
nums.sort(); // [10, 2, 21, 3, 9] — wrong, string order
nums.sort((a, b) => a - b); // [2, 3, 9, 10, 21] — correct

reverse() flips the array in place.

slice: extract a portion

slice(start, end) returns a new array from start up to (but not including) end. The original is unchanged:

const arr = ["a", "b", "c", "d", "e"];
const portion = arr.slice(1, 4);
console.log(portion); // ["b", "c", "d"]

join and toString

join() converts an array to a string, using a separator you choose. toString() does the same with commas. For more complex string formatting, pair array output with template literals:

const parts = ["Hello", "world"];
parts.join(" "); // "Hello world"
parts.toString(); // "Hello,world"

Mutating methods vs non-mutating alternatives (ES2023)

ES2023 introduced non-mutating counterparts for the most-used mutating methods. These return a new array and leave the original alone, which is better for functional patterns and React state:

MutatingNon-mutating alternative
sort()toSorted()
reverse()toReversed()
splice()toSpliced()
arr[i] = valwith(i, val)
const nums = [3, 1, 2];
const sorted = nums.toSorted((a, b) => a - b);
console.log(nums);   // [3, 1, 2] — unchanged
console.log(sorted); // [1, 2, 3]

Common pitfalls

Forgetting curly braces when storing objects in arrays

If you’re building an array of objects, every object needs its own curly braces and must be separated by commas:

// Correct
const products = [
    { name: "Shirt", price: 20 },
    { name: "Shoes", price: 60 }
];

// Wrong — JavaScript cannot parse this
// const products = [ name: "Shirt", price: 20, name: "Shoes", price: 60 ];

Forgetting that map, filter and reduce return new arrays

These methods do not change the original array. If you call filter() but don’t save the result, nothing happens:

const nums = [1, 2, 3, 4];

// This does nothing useful
nums.filter(n => n > 2);

// Save the result
const big = nums.filter(n => n > 2);
console.log(big); // [3, 4]

Using the wrong method for the task

forEach cannot return a value or break early. If you need a new modified copy, use map. If you need only certain elements, use filter. If you need to stop mid-loop or branch on a value, a classic for loop with a switch statement handles that well.

Key Takeaways

  • A JavaScript array stores any mix of data types (numbers, strings, objects and other arrays) in an ordered, indexed list.
  • Always use array literals ([]) rather than new Array() to avoid the single-argument trap.
  • push, pop, shift, unshift and splice all mutate the original array. concat, slice, map, filter and reduce return a new array.
  • Use Array.isArray() rather than typeof to reliably detect arrays.
  • ES2023 non-mutating alternatives (toSorted, toReversed, toSpliced, with) are available in all modern browsers.
  • Spread syntax and Array.from() create shallow copies. Use structuredClone() for deep copies.
  • map transforms, filter narrows and reduce aggregates. Learn these three and you cover most data-processing tasks.

Frequently Asked Questions

What is an array in JavaScript?

An array is a variable that stores an ordered list of values. Each value has a numeric index starting at 0, and the list can hold any data type.

How is a JavaScript array different from arrays in other languages?

JavaScript arrays can hold any mix of data types in one list. Most typed languages (Java, C, C++) require every element to be the same type.

How do you declare an array in JavaScript?

Use square bracket syntax: const arr = [value1, value2]. You can also start with an empty array const arr = [] and add elements later.

Can you store different data types in a single JavaScript array?

Yes. Numbers, strings, booleans, objects and even other arrays can sit together in the same array.

What is the difference between push and unshift?

push() adds elements to the end of an array. unshift() adds them to the beginning. Both return the new array length.

How do you check if a variable is an array?

Use Array.isArray(variable). It returns true if the value is an array, unlike typeof which returns "object" for any object.

What is the difference between slice and splice?

slice(start, end) returns a copy of a portion of the array without changing the original. splice(start, deleteCount) modifies the original array by removing, replacing or inserting elements.

Arrays are at the center of almost every JavaScript program. Knowing when to reach for map vs filter vs a plain for loop will make your code noticeably shorter and easier to follow.

Aditya Gupta
Aditya Gupta
Articles: 512