Skip to main content

Arrays

Arrays are a fundamental datatype in JavaScript. Like arrays in other languages, they represent an ordered collection of values, where each element has a numeric position in the array. Numbering begins at zero. Unlike other languages, JavaScript arrays are not typed; elements of the same array may be of different types. JavaScript arrays are also dynamic - the size can grow and shrink during execution so there is no need to declare a size up front.

  • JavaScript arrays can hold values of different types.
  • The size of an array is dynamic. It can grow and shrink during program execution.
  • No need to specify the array size up front.
  • Arrays can be constructed with either the new keyword with the Array() constructor, or with array literal notation - [ ]- - square brackets
  • length returns the size of the array

creating arrays

You can create an empty array in several different ways:

let scores = new Array();
let artists = Array();
let emptyArray = [];

If you know the number of elements, you can create an array of a particular size:

let scores = Array(10);

You can create and initialize an array with values:

let scores = new Array(9,10,8,7,6);
let colors = ['red', 'green', 'blue'];

length

length returns the size of the array:

console.log(colors.length);  

outputs this to the console:

bash
TERMINAL

3

push and pop

To add elements dynamically to the end of an array use push:

myarray.push('new item');

Then, you can remove an item from the end of an array with pop:

lastitem = myarray.pop();

In the example below, we create an array, teams, with three elements. We add a new team with push and then remove the last element added with pop:

let teams = ['Falcons', 'Saints', 'Panthers'];
teams.push('Jaguars'); // added to end
console.log(teams);

const lastElement = teams.pop(); // pop last element
console.log(lastElement);

and this is the output:

bash
TERMINAL

[ 'Falcons', 'Saints', 'Panthers', 'Jaguars' ] Jaguars

indexOf and isArray

You can find the index of an array element with the indexOf() method. Determine if a value is an array with the isArray() method:

let index = teams.indexOf('Panthers'); 
console.log(index);

console.log(Array.isArray(teams));
bash
TERMINAL

2
true

Destructuring

Array destructuring provides a convenient way to extract elements from an array or properties from objects in a single line of code.

Destructuring provides short, clean syntax to unpack to distinct variables:

  • values from an array
  • properties from objects

With this array:

const league = ["Steelers", "Falcons", "Patriots", "Browns"];

we can extract teams from the array with:

let team1 = league[0];
let team2 = league[1];

but a cleaner approach is to use destructuring:

let [team1, team2] = league;

Spread

The JavaScript spread operator (...) provides a concise way to expand an array into its individual elements. This functionality is useful in several situations:

  • copying arrays
  • merging arrays
  • adding elements to an array
  • passing elements of an array as arguments

copying

The spread operator is a convenient way to create a copy of an array.

let a = [1,2,3];
let copy = [...a];
console.log(copy);

yields the following to the console:

bash
TERMINAL

[ 1, 2, 3 ]

If I change an element of the copy, does that affect the original?

copy[0] = 0;
console.log(a[0]);
console.log(copy[0])

yields the following to the console:

bash
TERMINAL

1 0

merging

Use the spread operator to combine multiple arrays into a new array.

const numbersOne = [1, 2, 3];
const numbersTwo = [4, 5, 6];
const numbersCombined = [...numbersOne, ...numbersTwo];
console.log(numbersCombined);

yields this output:

bash
TERMINAL

[ 1, 2, 3, 4, 5, 6 ]

adding elements

New elements can be easily added to an array, either at the beginning, end, or in the middle, by spreading an existing array and including the new elements.

let a = [1, 2, 3];
let b = [0, ...a, 4];
console.log(b);

yields the following output:

bash
TERMINAL

[0,1,2,3,4]

info

The three dots "spread" the array a so that its elements become elements within the array literal being created. Essentially, the ...a is replaced by the elements of a.

passing array elements

When a function expects individual arguments, the spread operator can be used to expand an array into those arguments.

function sum(a, b, c) {
return a + b + c;
}
const values = [1, 2, 3];
console.log(sum(...values));

yields the following output:

bash
TERMINAL

6

for/of

The easiest way to loop through each element of an array is with the for/of loop. for/of:

  • runs once for each element
  • works with iterable objects:
    • arrays,
    • strings,
    • sets, and
    • maps

Set it up using the keywords as in this sample code:

for ( variable of iterable_object) {
body
}

The following two loops are functionally equivalent:

years = [1952, 1999, 2001, 2011, 2020, 2025];

for (let i = 0; i < years.length; i++) {
let yr = years[i];
console.log(yr);
}

for (let yr of years) {
console.log(yr);
}

Both implementations yield:

bash
TERMINAL

1952 1999 2001 2011 2020 2025

Strings are iterable objects so can be iterated with:

const iterable = "boo";

for (const value of iterable) {
console.log(value);
}

Results in the following output:

bash
TERMINAL

b o o

Array methods

forEach

ForEach iterates through an array invoking a function you specify for each element. You pass the function as the first argument and forEach() then invokes your function with (optionally) three arguments:

  • the value of the array element,
  • the index of the array element
  • the array itself If you only care about the value of the array element, you can write a function with only one parameter - the additional arguments will be ignored. For example, we can sum the elements:
let data = [1,2,3,4,5];
let sum = 0;
data.forEach(value => sum += value);
console.log(`result of forEach: ${sum}`);

which outputs:

bash
TERMINAL

result of forEach: 15

We can increment each array element, :

data.forEach((v, i, a) => a[i] = v + 1);
console.log(`incremented array: ${data}`);

which yields:

bash
TERMINAL

incremented array: 2,3,4,5,6

To execute a function on each element:

numbers = [1,2,3,4,5];
function print(element) {
console.log(element)
}
numbers.forEach(print);

map

map() passes each element of the array on which it is invoked to the function you specify and returns a new array of the same size containing the values returned by your function.

The function you pass to map() is invoked in the same way as a function passed to forEach(). For the map() method, however, the function you pass should return a value; that value becomes the entry in the new array.

info

map returns a new array. The array map is invoked on is not modified.

Consider this example:

const numbers = [1,2,3,4,5];

const newNumbers = numbers.map(function (num) {
return num * 2;
})
console.log(newNumbers);

or use an arrow function. Which is more readable?

const newNumbers = numbers.map ( num => num * 2 );
console.log(newNumbers);

Both output:

bash
TERMINAL

[ 2, 4, 6, 8, 10 ]

Consider this list of movies in watchList:

watchList = [
{
"Title": "Inception",
"Year": "2010",
"Rated": "PG-13",
"Released": "16 Jul 2010"
},
{
"Title": "Interstellar",
"Year": "2014",
"Rated": "PG-13",
"Released": "07 Nov 2014",
},
{
"Title": "The Matrix",
"Year": "1999",
"Rated": "R",
"Released": "31 March 1999",
}];

To create a ratings array that includes just the Title and Rated property of each movie we could use push on each element:

let ratings = [];
for(let i=0; i < watchList.length; i++){
ratings.push({title: watchList[i].Title,
rating: watchList[i].Rated});
}
console.log(ratings);

or we could accomplish this with map:

const ratings = watchList.map(movie => ({
title: movie.Title,
rating: movie.Rated
}))
console.log(ratings);

Both versions yield:

[
{ title: 'Inception', rating: 'PG-13' },
{ title: 'Interstellar', rating: 'PG-13' },
{ title: 'The Matrix', rating: 'R' }
]

filter

Filter: creates a new array with all elements that pass the test implemented by the provided function. filter() returns a subset of the elements of the array.

The function passed should return true or false.

For example, to keep the numbers less than 3 in a new array:

const numbers = [1,2,3,4,5];
let underThree = numbers.filter(function (num) {
return num < 3;
})
console.log(`filtered: ${underThree}`);

The above filter on numbers yields:

bash
TERMINAL

filtered: 1,2

Or to keep even numbers in the new array:

let evenNumbers = numbers.filter(n => n%2 === 0)
console.log(`filtered: ${evenNumbers}`)

The above filter results result in the following console output:

bash
TERMINAL

filtered: 2,4

info

filter returns a new array. The array filter is invoked on is not modified.

find / findIndex

find() and findIndex() iterate through the array looking for elements where the passed function returns true. Similar to filter, you are to pass a boolean function; unlike filter, find() stops iterating the first time a matching element is found. findIndex() returns the index and find() returns the matching element. If no matching element is found, find() returns undefined and findIndex() returns -1.

Consider these examples:

const numbers = [1,2,3,4,5];
let mult_5 = numbers.find(x => x%5 === 0)
let mult_7 = numbers.find(x => x%7 === 0)
let ind_3 = numbers.findIndex(x => x === 3)

console.log(mult_5);
console.log(mult_7);
console.log(ind_3);

yields the following output:

bash
TERMINAL

5 undefined 2

sort / toSorted

sort orders the elements of the array in place and returns the sorted array. When called with no parameters, sort() sorts the elements in alphabetical order.

To sort an array into some order other than alphabetical, a comparator function must be provided. The function determines the order of the elements. It takes two arguments, often referred to as a and b, and returns:

  • A negative value if a should come before b
  • Zero if a and b are considered equal (keeps original order)
  • A positive value if a should come after b
info

sort modifies the original array


const fruits = ["Banana", "Orange", "Apple", "Mango"];
fruits.sort();
console.log(fruits);

const a = [33, 4, 1111, 222];
a.sort(); // alphabetical order
console.log(a);

a.sort((a,b)=> a-b); // ascending order
console.log(a);

a.sort((a,b)=> b-a); // descending order
console.log(a);

Yields output as follows:

bash
TERMINAL

[ 'Apple', 'Banana', 'Mango', 'Orange' ] [ 1111, 222, 33, 4 ] [ 4, 33, 222, 1111 ] [ 1111, 222, 33, 4 ]

The toSorted() method is available in newer JavaScript. toSorted creates a new array with the sorted elements, leaving the original array in tact. Here's an example:

const numbers = [10, 2, 5];
const sortedNumbers = numbers.toSorted((a, b) => a - b);
console.log(numbers);
console.log(sortedNumbers);
bash
TERMINAL

[ 10, 2, 5 ] [ 2, 5, 10 ]

reduce

Reduce combines the elements of an array, using the function you pass as a parameter, to produce a single value. reduce() takes two arguments: the function that performs the reduction operation and the second (optional) argument is an initial value to pass to the function.

The task of the function is to combine or reduce two values to a single value and return the reduced value.

const numbers = [1,2,3,4,5];
let ss = numbers.reduce((x,y) => x+y, 0)

let prod = numbers.reduce((x,y) => x*y, 1)

console.log(ss);
console.log(prod);

yields the following output:

bash
TERMINAL

15 120

every and some

every() and some() apply a predicate function you specify to the elements of the array, then return true or false.

const numbers = [1,2,3,4,5];
let e = numbers.every(x=> x < 10)
let s = numbers.some(x => x%2 === 0)
console.log(e);
console.log(s);

As seen below, both every and some return true because all numbers are less than 10 so every results in true. Also at least one number in the numbers array is even so some returns true as well. Output of every and some in above example:

bash
TERMINAL

true true