JavaScript: Arrays — Array Methods

JavaScript Array Methods

Learning outcomes:

  • Joining arrays together using concat()
  • Filling an array using fill()
  • Using slice() to slice an array
  • Adding/removing elements at the end — push() and pop()
  • Adding/removing elements at the start — unshift() and shift()
  • Adding/removing elements at an arbitrary index — splice()
  • Reversing an array using reverse()
  • Finding the index of an element using indexOf() and lastIndexOf()
  • Existential and universal quantification using some() and every()
  • Filtering items via filter()
  • Joining array elements using join()
  • Mapping to a new array via map()

Introduction

Arrays are highly useful for storing ordered collections of data but not until they are blended together with some useful methods.

In this chapter, we shall get an overview of the most fascinating methods available to all array instances in JavaScript.

Joining multiple arrays together

To join — or better to say, concatenate — two or more arrays together into a single array, we use the concat() method.

Call it on a given array whose elements you want to appear first in the final array and then pass the rest of the arrays one by one, as arguments.

Something as follows:

arr1.concat(arr2, arr3, ...., arrN)

The order in which the arrays appear in the expression above is exactly the same order in which their elements are laid out in the final array.

The concat() method does NOT modify the original array; instead, it returns a new array composed of all the individual arrays together.

Let's say we have three different lists of numbers which represent the marks of three different students in recent exams out of 100:

JavaScript
let a = [75, 54, 70],
let b = [94, 60, 78];
let c = [67, 80, 81];

Now we would like to collect all these marks in one, single array and then display them in sorted format.

For this we'll need to first join all the three arrays together and then perform the sorting on the final array obtained in the end. In the code below, we accomplish this idea using concat() and finally log the resulting array:

JavaScript
let a = [75, 54, 70];
let b = [94, 60, 78];
let c = [67, 80, 81];

let allNums = a.concat(b, c);
console.log(allNums.sort(function(a, b) { return a - b; }));
[54, 60, 67, 70, 75, 78, 80, 81, 94]

Filling an array

If we wish to set each element of an array to the same value, we could iterate over it and assign each index that very value. An example follows:

JavaScript
// Fill array `arr` with value `v`
for (let i = 0; i < arr.length; i++) {
   arr[i] = v;
}

Fortunately, there's a much easier way — use the fill() array method.

Just pass fill() the value to fill the given array with:

arr.fill(value)

The return value of fill() is the filled array. Note that fill()mutates the original array (and then returns it).

There are two variants of fill(): one that allows us to specify the starting point, and one that allows us to specify both the starting and the ending point for the filling operation.

Consider the examples below:

[1, 2, 3, 4].fill(0)
[0, 0, 0, 0]
[1, true, Infinity].fill(100)
[100, 100, 100]

If the array is empty, there won't be any consequence of calling fill() on it, as can be seen below:

[].fill(0)
[]

One of the most common applications of fill() is to pre-initialize a sparse array, as we learned in the passing by in the last chapter.

The idea is to first create an array using new Array(n) with n empty spaces in it and then fill each of those empty slots with a given value using fill().

This is extremely handy when we have to work with a preinitialized array, where otherwise creating the array manually using literals would be quite a strenuous activity.

Let's take an example.

Suppose we have to create an array holding 100 values, each initialized to 0. As you would agree, creating this array literally would be quite a difficult and error-prone task.

A better way would be to create an array to the desired length using new Array(100) and then fill it with the value 0. Something as follows:

JavaScript
let nums = new Array(100).fill(0);

console.log(arr[0]);
console.log(arr[50]);
console.log(arr[99]);
0
0
0

Voila! All of the three elements inspected are equal to 0.

As stated earlier and now reiterating it, without calling fill() on it, the array returned by new Array(n) consists of empty slots, accessing which would yield undefined.

Slicing an array

To extract out a given subarray from an array, we could use the slice() method.

The slice() method takes a starting (inclusive) and ending (exclusive) index and returns a slice of the array, i.e. a subarray, in that range.

Shown below is its syntax:

arr.slice([start[, end]])

As per the syntax, both start and end are optional (hence, the brackets around them):

  • start specifies the index where to start the slicing. This is inclusive, and defaults to 0.
  • end specifies the index where to end the slicing. This is exclusive, and defaults to arr.length.
We saw a similar slice() method, with exactly the same syntax of arguments, for strings back in the JavaScript String Methods chapter.

Let's consider a couple of examples:

JavaScript
let nums = [1, 2, 3, 4, 5];

console.log(nums.slice(0, 0)); // []
console.log(nums.slice(0, 1)); // [1]
console.log(nums.slice(1, 4)); // [2, 3, 4]

In the first slice() statement, calling slice(0, 0) returns an empty array because the slicing begins at 0 and ends right before 0 (at -1).

In the second statement, calling slice(0, 1) returns the array [1] by beginning slicing at index 0 and ending it just before 1 (i.e. 0).

In the last statement, calling slice(1, 4) returns the array [2, 3, 4] because slicing this time begins at index 1 and ends just before index 4. This accounts for the indexes 1, 2 and 3 (4 being exclusive).

Figure out the return value of nums.slice() for the nums array above.

Keep in mind the default values of both the start and end arguments.

  • undefined
  • []
  • [1, 2, 3, 4]
When slice() is called without any arguments, the slice beings at index 0 and ends at the length of the array, i.e. it spans the entire array. This effectively means to slice the entire array and this goes with choice (C).

Adding/removing elements at the end

As we saw in the previous chapter, to add an element, or a set of elements, at the end of an array, we could use the push() method.

The push() method adds an element to the end of an array.

The syntax is pretty straightforward:

arr.push(item1, item2, ..., itemN)

item1, item2, all the way to itemN, represent items to be added to the array in that very order.

push() mutates the original array and, therefore, changes the length of the calling array.

Let's use push() to add a couple of elements to an array:

JavaScript
let nums = [1, 2];

nums.push(3);
console.log(nums);

nums.push(4);
console.log(nums);
[1, 2, 3]
[1, 2, 3, 4]

In a similar way that we could add an element to the end of an array, we could remove it from there as well. For this, we have the pop() method.

The pop() method removes an element from the end of an array.

Since pop() merely removes the last element from an array, it doesn't require any arguments:

arr.pop()

pop() returns the element removed. This is useful because, often times, we have to use the value in the program before removing it.

Following from the last code, let's remove the last two elements using pop():

JavaScript
let nums = [1, 2];

nums.push(3);
nums.push(4);
console.log(nums);

console.log('Removing', nums.pop());
console.log('Removing', nums.pop());
console.log(nums);
[1, 2, 3, 4]

Removing 4
Removing 3
[1, 2]

Simple, wasn't it?

Adding/removing elements at the start

As we saw just right now, push() and pop() serve to add and remove stuff from the end of a given array. In JavaScript, and most programming languages that support dynamic arrays, we could do so at the start of the array as well.

The methods used in this case are unshift() and shift().

The unshift() method adds an element to the start of an array.

Parameter-wise, it's same as push():

arr.unshift(item1, item2, ..., itemN)

The given arguments are added to the start of arr. Simple.

Let's consider a quick example:

JavaScript
let nums = [1, 2];

nums.unshift(3);
console.log(nums);

nums.unshift(4);
console.log(nums);
[3, 1, 2]
[4, 3, 1, 2]

To remove an element from the start of an array, we use the shift() method.

The shift() method removes an element from the start of an array.

It's syntactically the same as pop():

arr.shift()

The return value of shift() is the element removed.

Let's consider a quick example following from the last code snippet above:

JavaScript
let nums = [1, 2];

nums.unshift(3);
nums.unshift(4);
console.log(nums);

console.log('Removing', nums.shift());
console.log('Removing', nums.shift());
console.log(nums);
[4, 3, 1, 2]

Removing 4
Removing 3
[1, 2]

Adding/removing elements at arbitrary indexes

To add and/or remove stuff from an array starting at an arbitrary index, instead of the beginning or end of the array, we have the splice() method at our dispense.

splice() is meant to add/remove elements from an array, in-place, starting from a given index.

Note that splice() mutates the original array.

Here's its syntax:

arr.splice([index[, deleteCount[, item1[, item2[, ...[, itemN]]]]]])
  1. index is the index where to begin the addition and/or removal of stuff. It can also be negative, in which case it's taken to be relative from the end of the array. It defaults to 0.
  2. deleteCount specifies the number of items to delete starting from the position index. If index is not specified, i.e. splice() is called without any arguments, deleteCount is 0. Otherwise, it is set to arr.length - index, i.e. removes all elements upto the end of the array, starting from index.
  3. item1, item2, all the way itemN, specify the elements to add at index. If omitted, nothing is added.

The return value of splice() is an array holding the deleted items of the main array. If nothing is deleted, i.e. deleteCount is 0, an empty array is returned.

Time for some examples...

Let's say we have the following array and want to remove the second element from it:

JavaScript
let nums = [1, 50, -6, -20, 22];

How would we do so?

  • Well, the second element is at index 1, and this is the position where the removal should begin; hence the first index arg to splice() becomes 1.
  • Moving on, since only one element is to be deleted, deleteCount would also be 1.
  • And finally, because nothing ought to be added, no args follow along.

Below, we perform the removal, and log both nums and the array holding the removed item:

JavaScript
let nums = [1, 50, -6, -20, 22];
let deletedNums = nums.splice(1, 1);

console.log(nums);
console.log(deletedNums);
[1, -6, -20, 22]

[50]

See how the deleted element 50 is accessible as an element of deletedNums.

In a real-world application, you might want to work with the set of removed items and that's where the return value of splice() could help.

Let's see a couple more examples.

Say we have to delete the second last element from an array arr. What would the set of args to splice() be?

Simple — nums.splice(-2, 1).

An illustration follows:

JavaScript
let nums = [1, 50, -6, -20, 22];
let deletedNums = nums.splice(-2, 1);

console.log(nums);
console.log(deletedNums);
[1, 50, -6, 22]

[-20]

What if we want to remove nothing from an array, but rather add two elements at the second position? Hmm..

We'll call nums.splice(1, 0, ele1, ele2).

  • We need to operate on the second position in the array, hence the first argument 1.
  • Moreover, we wish to remove nothing from this position, hence the second argument 0 (which specifies the number of items to delete).
  • Finally, we wish to add two elements, hence the subsequent two arguments.

An illustration follows:

JavaScript
let nums = [1, 50, -6, -20, 22];
let deletedNums = nums.splice(1, 0, Infinity, NaN);

console.log(nums);
console.log(deletedNums);
[1, Infinity, NaN, 50, -6, -20, 22]

[]

Since nothing is removed in the array nums above, splice() returns an empty array.

splice() without any arguments

Calling splice() without any arguments has no effect on the given array and returns an empty array itself (since nothing is deleted in this case):

JavaScript
let nums = [1, 2, 3];

console.log(nums);
console.log(nums.splice());
[1, 2, 3]

[]

Reversing an array

Want to reverse the order of elements of an array? Well, for this you need the reverse() method.

It's very simple in nature:

arr.reverse()

Note that as with sort(), reverse() mutates the original array and returns it back too.

Shown below is an example:

JavaScript
let subs = ["Chemistry", "Physics", "Math"];

console.log(subs.reverse());
console.log(subs);
['Math', 'Physics', 'Chemistry']

['Math', 'Physics', 'Chemistry']

In the first log statement, the reverse() method returns back the reversed version of subs and this is logged to the console. The second log statement outputs the same array as before. This confirms that the original array subs was mutated by subs.reverse().

If you don't want to mess up with the order of elements in the original array, make sure to make its copy and then call the reverse() method on that copy.

Finding the index of an element

Do you recall the indexOf() and lastIndexOf() methods all the way back from the JavaScript String Methods chapter?

Both of these methods are available on array instances as well and serve a similar purpose — to return the index of a given element, if found.

The best part is that they're identical syntactically, so I won't be going over their syntax again here.

Shown below are a couple of examples of indexOf():

[1, 2, 3, 4].indexOf(1)
0
[1, 2, 3, 4].indexOf(4)
3
[1, 2, 3, 4].indexOf(5)
-1
[1, 2, 3, 4].indexOf("1")
-1
[1, true, true, false].indexOf(true)
1

Similar to indexOf(), which finds the first match for a given value, the lastIndexOf() method finds the index of the last match of a given value.

Consider the snippet below:

[1, 2, 3, 4].lastIndexOf(1)
0
[1, 2, 3, 4].lastIndexOf(4)
3
[1, 2, 3, 4].lastIndexOf(5)
-1
[1, 2, 3, 4].lastIndexOf("1")
-1
[1, true, true, false].lastIndexOf(true)
2
[1, 1, 0, 1].lastIndexOf(1)
3

Existential and universal quantification

In elementary logic, specifically in predicate logic, there is this idea of some item in a given set of items meeting a certain condition. We call this existential quantification.

A similar idea is that of universal quantification, where every single item meets the given condition.

These ideas of checking whether in a set of items, at least one or all elements meet a certain condition are present in JavaScript arrays as well. They are exposed by the some() and every() methods, respectively.

some() takes a function and returns true if the function evaluates to true for at least one element in the calling array.

Time to see its syntax:

arr.some(callbackFn)

callbackFn is a function that is run for every element of arr until it returns a truthy value. Here's the syntax of the callback function:

callbackFn(element, index, arr)

  1. element is the element of arr currently under inspection.
  2. index is the index of element.
  3. arr holds a reference to original array.

Let's consider a quick example.

Say we want to confirm whether in a list of numbers there is at least one square number. We could solve this by laying out the callback function as follows:

JavaScript
function isSquare(element) {
   return Number.isInteger(element ** 0.5);
}

If any one element in the list of numbers is a square, isSquare() would return true for it and hence cause some() to return true as well.

Shown below are a couple of examples:

JavaScript
function isSquare(element) {
   return Number.isInteger(element ** 0.5);
}

let nums = [1, 2, 3];
console.log(`Square in ${nums}`, nums.some(isSquare));

nums = [2, 3, 4];
console.log(`Square in ${nums}`, nums.some(isSquare));

nums = [2, 3, 5, 7];
console.log(`Square in ${nums}`, nums.some(isSquare));

nums = [2, 3, 5, 7, 49, 100];
console.log(`Square in ${nums}`, nums.some(isSquare));
Square in 1,2,3: true
Square in 2,3,4: true
Square in 2,3,5,7: false
Square in 2,3,5,7,49,100: true

Following from the fact that for some() to return true, there has to be at least one element in the array for which the callback function returns true, when the array is empty i.e. has not elements, some() returns false.

Consider the following code:

JavaScript
function isSquare(element) {
   return Number.isInteger(element ** 0.5);
}

console.log([].some(isSquare));
false

In the same way, to check whether every single element in an array meets a given condition, we could use the every() method.

The method every() takes a function and returns true if the function evaluates to true for every single element in the calling array, or otherwise false.

It's syntactically identical to some():

arr.every(callbackFn)

Check out the syntax for callbackFnabove.

The main difference is that the given callback function is run for every element in the given array and if, for any one, it returns a falsey value, every() returns false as well. It's only when the function returns a truthy value for every element in the array that every() returns true.

Let's say we want to confirm whether a student passed in all exams. The passing marks are above 50. If the student's marks were modeled by an array marks, we could use every() to solve this task.

Shown below is an illustration:

JavaScript
function above50(marks) {
   return marks >= 50;
}

let marksList = [35, 80, 54, 90, 60];
console.log(marksList.every(above50));

marksList = [78, 86, 70, 95, 71];
console.log(marksList.every(above50));
false
true

Following from the fact that for every() to return false, there has to be at least one element in the array for which the callback function returns false, when the array is empty i.e. has not elements, every() returns true.

Consider the following code:

JavaScript
function above50(marks) {
   return marks >= 50;
}

console.log([].every(above50));
true

Filtering elements

To obtain only those elements from an array that meet a given condition, we use the filter() method.

filter() takes in a callback function and returns an array containing all the elements in the calling array for which the callback function returns a truthy value.

arr.filter(callbackFn)

The syntax of this callback is the same as the one provided to the some() and every() methods discussed above. That is:

callbackFn(element, index, arr)

where element is the current element under consideration, index is its index in the array, and arr is the array.

If you think for a second, the word 'filter' is quite a sensible name for this method. It says to 'filter in' elements from an array based on a given condition.

I use the phrase 'filter in' because the callback provided to filter() specifies which elements we are interested in, NOT those elements that we wish to filter out, i.e. ignore.

Pretty clever naming!

Say we want to extract out all positive values from an array of numbers. For this we'll set up the callback function as follows:

JavaScript
function positiveNumber(num) {
   return num > 0;
}

This would return true only for those numbers that are greater than 0. Let's use this function along with filter() on a couple of arrays and see the outcome in each case:

JavaScript
function positiveNumber(num) {
   return num > 0;
}

let nums = [10, 5, -4, -1, 50, 34, -27];
console.log(nums.filter(positiveNumber));

nums = [0, 15, 0, -6, -1, -4, -0.5, 3.1, 10.5];
console.log(nums.filter(positiveNumber));
[10, 5, 50, 34]

[15, 3.1, 10.5]
This feature of filtering out elements from an array could also be accomplished using loops, but at the cost of longer and more complicated code. The filter() method is no doubt very quick and concise.

Create an array evens by filtering out all the even-indexed elements from the following nums array:

JavaScript
let nums = [1, 10, 5, 33, 198, 0, 5, 8];

Your evens array shall be equal to [1, 5, 198, 5] as these elements have even indexes in nums0, 2, 4, and 6 respectively.

Think of the second parameter of the callback function passed to filter().

JavaScript
let nums = [1, 10, 5, 33, 198, 0, 5, 8];

let evens = nums.filter(function(e, i) {
   return i % 2 === 0;
});

Joining elements together

When working with arrays, it's extremely common to go into a string representation by joining the individual elements together.

If we just want to join the elements with a comma in betweeen, we can call the toString() method or even just use the array in the context of a string, e.g. in a string concatenation operation.

Both of these are shown below:

[1, 2, 3, 4].toString()
'1,2,3,4'
[1, 2, 3, 4] + ''
'1,2,3,4'
'The numbers are: ' + [1, 2, 3, 4]
'The numbers are: 1,2,3,4'

This joins the array elements with a comma (,) in between, without any space around it. However, if we want a different separator, then we need to use the join() method.

join() accepts an optional, string argument which is the separator to put in between the array's elements:

arr.join([separator])

By default, separator is set to ',', which means that arr.join() is effectively the same as calling arr.toString().

The return value of the join() method is a string containing all elements of arr separated by separator.

A separator is sometimes also known as a delimiter.

In the code below, we create an array nums and then output it with each element being separated from the other one using a space:

JavaScript
let nums = [1, 2, 10, 50, 100];

console.log(nums.join(' '));
1 2 10 50 100

Mapping an array

It's a common idea to iterate over an array and map each of its elements onto a new element. These mapped elements are put in a new array.

For instance, suppose we have a list of positive integers. We could create a list of squares out of it by mapping each integer to the square of that integer. Similarly, we could even obtain a list of cubes.

In JavaScript, we use the map() method to create a new array based on a given array, with a mapping function.

The map() method takes a function and returns a new array comprised of elements returned by the function for each element of the calling array.

In its simplest form, we just ought to provide the mapping function to map(), that's it:

arr.map(mappingFn)

Let's now talk about the syntax of this mapping function, mappingFn. It's similar to the callback function provided to some(), every(), and filter().

mappingFn(element, index, arr)

  1. element is the element of arr currently under inspection.
  2. index is the index of this element.
  3. arr holds a reference to the array in question.

Let's consider a couple of examples...

Below we have an array ints which is used to create two more arrays squares and cubes by means of square and cube functions, respectively:

JavaScript
function square(int) { return int ** 2 };
function cube(int) { return int ** 3 };

let ints = [0, 1, 2, 3, 4, 5];

let squares = ints.map(square);
console.log(squares);

let cubes = ints.map(cube);
console.log(cubes);

// Let's see if `ints` has been modified
console.log(ints);
[0, 1, 4, 9, 16, 25]

[0, 1, 8, 27, 64, 125]

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

The last log here confirms the fact that calling map() on an array does not mutate it.

Going ahead, a common practice you'll see in coding competitions out there is to use this notion of mapping to convert a list of stringified numbers into a list of numbers.

In the code below, we convert a string of space-delimited numbers into an array of numbers using a couple of handy methods, including map():

JavaScript
let str = '10 -5 40 1 0 0 3';

let nums = str.split(' ').map(Number);
console.log(nums);
[10, -5, 40, 1, 0, 0, 3]

Time to understand what's happening over here...

str.split(' ') breaks apart str at each space (' ') character and returns back an array of the left-over strings, as follows:

str.split(' ')
['10', '-5', '40', '1', '0', '0', '3']

Next up, map(Number) goes over this array of strings and runs the Number() function over each string. Recall that, given an argument, Number() converts it into a number.

['10', '-5', '40', '1', '0', '0', '3'].map(Number)
[10, -5, 40, 1, 0, 0, 3]

All in all, this is an elegant way to convert a string of numbers into an array of numbers, without having to spin up a complex piece of code containing a loop.

Spread the word

Think that the content was awesome? Share it with your friends!

Join the community

Can't understand something related to the content? Get help from the community.

Open Discord

 Go to home Explore more courses