Working with Arrays

Overview

A JavaScript array is an ordered collection of data items that can be used to implement complex data structures such as lists, queues and stacks. We have talked about the distinctions between primitive and complex data types elsewhere in this section, and have stated that any datatype that cannot be classed as a primitive datatype is considered to be an object.

There is a clear distinction in JavaScript, however, between arrays and other kinds of object. We can think of an array as a highly specialised kind of object - one in which each data item (or element) occupies a specific position within the array, and can be accessed using a numerical array index. JavaScript array indexes are zero based, so the first item in an array is found at index 0, the second item is found at index 1, and so on.

Almost all mainstream programming languages support arrays. However, in most other programming languages (C, C++, C#, Visual Basic, and Java for example), all of the elements of an array must have the same datatype. Because an array in JavaScript is an object, the elements in a JavaScript array can have different datatypes. For example:

let person = ["John","Smith",25]; // this is an array

So, what is the difference between an array and any other kind of object? In order to simplify matters somewhat, from this point forward, when we talk about objects we will be referring to objects that are not arrays. The code above declares an array variable called person that contains data about a person – in this case, a person's first name, last name and age. This is probably not the best way to use an array, however. We would be better off using an object to store this kind of data. For example:

let person = {
  firstName: "John",
  lastName: "Smith",
  age: 25
}; // this is an object:

One obvious difference between our array declaration and the object declaration is that we enclose the data items in the person array using square brackets ([]), whereas the data items in the person object are enclosed between curly braces ({}). The second thing you will have noticed is that the data items in the person array are presented as a comma separated list of values, whereas the data items in the person object are listed as key-value pairs.

We even use a different terminology to describe data items, depending on whether we are talking about an array or an object. In an array, each data item is an array element. In an object, each data item is called a property. Individual array elements are accessed using an array index, i.e. an integer value that specifies the elements position within the array, whereas an object property is accessed using the property name associated with it.

We'll be taking a more detailed look at objects elsewhere in this section. For now, it is enough to remember that an array is a special type of object that we can use to create ordered collections of data items and store them in a single variable, and that each array element can be accessed using a numerical index. And, despite the differences described above, an array can store the same kind of values as an object, including strings, numbers, Boolean values, objects, and even other arrays.

Just to complicate matters, we should also point out that, because an array is an object, it can also have properties. One important property that all arrays have is the length property. For example:

let digits = [1,2,3,4,5,6,7,8,9,0];
console.log(digits.length) // 10

We can also define our own properties for an array, however. For example:

let myNumbers = [2,3,5,7,11,13,17,19];
myNumbers.numType = "prime";
console.log(myNumbers); // Array(8) [2,3,5,7,11,13,17,19]
console.log(myNumbers.numType); // prime

We have given the myNumbers array a property called "numType" and assigned the value "prime" to it. Note, however, that this does not directly affect the behaviour of the array itself. In fact, you are unlikely to encounter a situation in which you will need to assign any additional properties to an array.

If you are ever in any doubt as to whether the variable you are dealing with is an array or an object (this could be the case, for example, if you are maintaining code written by somebody else), using the typeof operator won't be of much help, because it returns the type object for arrays:

let myArray = ["Spring","Summer","Autumn","Winter"];
console.log(typeof myArray); // object

Fortunately, ECMAScript 2009 (also known as ES5) introduced the Array.isArray method, which makes life a little bit easier:

let myArray = ["Spring","Summer","Autumn","Winter"];
console.log(Array.isArray(myArray)); // true

One more thing to note is that neither the length of an array nor the data type of an individual array element is fixed. New array elements can be inserted into the array at any position, including index values that exceed the current array length, and the array elements do not have to occupy contiguous locations within the array - there can be gaps in the array, which means that JavaScript arrays are not guaranteed to be "dense". Existing array elements can be replaced by new array elements of the same or a different type. You can even have an array element that is itself an array! The following example demonstrates some of these points:

let myArray = ["cat","dog","rabbit"];
myArray[6] = "hamster";
console.log(myArray);
// Array(7) ["cat","dog","rabbit",<3 empty slots>,"hamster"]
myArray[0] = 9;
myArray[1] = "monkey";
console.log(myArray);
// Array(7) [9,"monkey","rabbit",<3 empty slots>,"hamster"]
let newArray = ["chicken","duck","goose"];
myArray[4] = newArray;
console.log(myArray[4]);
// Array(3) ["chicken","duck","goose"]

Arrays are useful when we want to create lists of data items than can be searched and sorted. We can add items to the list, delete items from the list, or change the value of a list item. We can also use arrays to implement collection types such as stacks and queues.

A stack is an abstract data type used in many programming languages. There are two principle operations we can perform on a stack - push, which adds a new value to the stack, and pop, which removes the last value added to the stack. It's called a stack because it behaves like a stack of dishes; at any time, we can place another dish on top of the stack, or we can take a dish from the top of the stack. Stacks are sometimes referred to as last in first out (LIFO) data structures.

A queue is another abstract data type used in programming. It's a bit like a stack except that, whereas new values are added to back of the queue, retrieved values are taken from the front of the queue. As an analogy, you can think of people queueing for a fairground ride. The operation to add a new item to the back of the queue is called enqueueing, and the operation to remove an item from the front of the queue is called dequeueing. Queues are sometimes referred to as first in first out (FIFO) data structures.

Array length

An array's length property returns an unsigned, 32-bit integer that specifies the number of elements in the array, regardless of whether or not one or more of the array elements is empty. More accurately, its value is one greater than the index of the last item in the array. This is highly efficient, because it means that the array elements do not need to be counted in order for the length property to be updated. If a new array element is added to the end of the array, the length property is simply incremented by one. If an element is removed from the end of the array, the length property is decremented by one. The following code illustrates the principle:

let myArray = ["cat","dog","rabbit"];
console.log(myArray.length); // 3
myArray.push("hamster");
console.log(myArray.length); // 4
let deleted = myArray.pop();
console.log(myArray.length); // 3

In fact, deleting an item from any position within an array, or inserting an item into an array at any position, will also change the value of the array's length property. Consider the following code:

const insects = ["ant","bee","spider","centipede","wasp"];
console.log(insects.length); // 5
insects.splice(2,2);
console.log(insects.length); // 3
insects.splice(2,0,"fly");
console.log(insects.length); // 4

The first line of code creates the insects array, and populates it with four elements. The third line of code removes two array elements, starting at index 2, which results in insects.length being decremented by two. The fifth line of code then inserts a new array element at index 2, resulting in insects.length being incremented by one. Each time some number of elements are inserted into an array, the array's length property is incremented by that number of elements. Similarly, each time some number of elements are removed from an array, the array's length property is decremented by that number of elements.

Simply changing the value of an existing array element will not result in a change in the array's length. Assigning a value to an array element that does not currently exist, on the other hand, will change the array's length. Consider the following code:

const myArray = [1,2,3,4,5];
console.log(myArray.length); // 5
arr[15] = 16;
console.log(myArray.length);
const iterator = myArray.values();
for (const value of iterator) {
  console.log(value);
}
// 1
// 2
// 3
// 4
// 5
// undefined
// 16
console.log(myArray.length); // 16
console.log(14 in myArray); // false
console.log(15 in myArray); // true

The first line of code creates the array myArray with five elements, and the length property of the array is reported as having the value 5. The third line of code assigns a value of 16 to array element myArray[15], which did not previously exist. The code then iterates through the array element values, and as you can see the array does indeed now have an array element with the value 16. Furthermore, the length property of myArray is now reported to have a value of 16.

The array elements myArray[5] through myArray[14] have not been assigned values. Their value is reported as undefined, and for all practical purposes they do not actually exist. The last two lines of code confirm this. Each line uses the in operator, which checks for the existence of a specific key within an object - in this case, the object in question is myArray, and the key is an array index. As you can see, there is no array element myArray[14]. If we had actually assigned the value undefined to this array element, however, it would exist:

myArray[14] = undefined;
console.log(14 in myArray); // true

Creating array elements with index values that increase the length of an array by an arbitrary amount is probably not something you should do unless you have a very good reason. Many of the standard JavaScript methods used to report on or manipulate arrays use the length property in various ways. If we use the push method to add an element to myArray, for example, the new element will be created with an index of 15 rather than filling one of the gaps in our array. That may of course be the intention, but there is usually no good reason for leaving gaps in arrays, since there are standard methods for inserting one or more new elements into an array at a specific position.

The final thing to note with respect to the length property is that it is writeable, i.e. it can be changed programmatically, and we can set an array's length property to any arbitrary value. Again, this is probably not something you should be doing with an existing array unless you have a very good reason.

Increasing array length in this way will not have any significant effect on the array itself, apart from the fact that the value reported for length will no longer reflect the actual number of elements in the array. Decreasing array length, on the other hand, will truncate the array, and in a non-reversible way. Any existing array elements beyond the new end-of-array will be deleted, and changing the array length back to its original value will not re-instate them. Of course, there may be occasions when that is what we intend. The simplest way to clear an array, for example, is to set its length property to zero:

myArray.length = 0;
console.log(myArray); // Array []

Creating an array

There are two primary ways of creating an array variable in JavaScript. The first method creates an array using an array literal. For example:

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

The above declaration creates an array variable called myArray containing five elements - the integer values 1 through 5. This is the easiest way to create an array variable, and probably the safest. Most sources seem to favour using this method of creating a JavaScript array, although some sources favour the second method, which uses the array constructor. For example:

const myArray = new Array(1,2,3,4,5);

Both of the above declarations will produce the same end result. However, consider the following declarations:

const myArray = [5];
const myArray = new Array(5);

You could be forgiven for thinking, based on the previous examples, that both of these declarations do exactly the same thing, but they don't. The first declaration, which uses an array literal, creates an array called myArray that contains a single array element - the integer value 5. The second declaration, which uses the array constructor, also creates an array variable called myArray, but this time with an array length of 5; none of the array elements are actually defined.

As you can see, the way the array constructor creates arrays will depend on the arguments it receives. If the only argument passed to the array constructor is an integer with a value in the range 0 - 2 32-1, it creates a new JavaScript array whose length property is set to that number. None of the array elements are assigned a value - not even one of undefined. We can think of them as empty slots:

const newArray = new Array(10);
console.log(newArray); // Array(10) [<10 empty slots>]

To avoid any possible confusion that may arise when using the array constructor, you can instead use the Array.of method to create an array. This method works in a similar way, except that it will always construct an array from the values passed to it, regardless of the number or type of those arguments. For example:

const myArray = Array.of(1,2,3,4,5);
console.log(myArray); // Array(5) [1,2,3,4,5]

const newArray = Array.of(5);
console.log(newArray); // Array [5]

Generally speaking, however, it is easier and faster to use an array literal to declare an array variable. It is also safer, for the simple reason that the array constructor may have been overridden elsewhere in the code, which means that array variables created using that constructor might behave in unexpected ways. Array variables declared using an array literal, on the other hand, will not usually be affected by any changes made to the array constructor because pretty much all current browsers interpret the array literal notation using a standard version of the array constructor, and will ignore the overridden version.

The syntax for creating array using an array literal is as follows:

const arrayName = [element0, element1, . . . , elementN];

The elements are enclosed within square brackets, and defined as a comma-separated list. If no values are included within the square brackets, the declaration creates an empty array. For example:

const myArray = [];
console.log(myArray); // Array []

It is also possible to create an array from an array-like or iterable object using the Array.from() method, which creates a shallow copied* array instance of the object. For example:

let myString = "Hello!";
const newArray = Array.from(myString);
console.log(newArray); // Array(6) ["H","e","l","l","o","!"]

The Array.from method can even be used to create an array from another array. This can be useful if we want make sure that every element in an array has an index property, because if there are any empty slots in the original array, Array.from will replace them in the new array with array elements that have the value undefined. For example:

const myArray = Array(2);
console.log(myArray); // Array(2) [<2 empty slots>]
const newArray = Array.from(myArray);
console.log(newArray); // Array(2) [undefined,undefined]

Note that the Array.from method can take an optional second argument, which is a mapping function that will be called on every element in the array. For example:

const myArray = [1,2,3,4,5];
function square(currentValue,index,array) {
  return currentValue * currentValue;
}
const sqrArray = Array.from(myArray,square);
console.log(sqrArray); // Array(5) [1,4,9,16,25]

One further question that often arises when it comes to array variables is "Should I use var, let or const to declare an array variable, and what difference does it make?". First of all, as we have said elsewhere in this section, using var to declare variables (regardless of type) can lead to potential problems, so we recommend that you don't use it. That leaves let and const.

Both let and const have block scope, which means they are only visible to code that lies within the block in which they are declared. Both let and const are also hoisted, which means that wherever they are used to declare variables within a block, those variables are visible to all of the code within that block, as if they had been declared at the top of the block. What is not hoisted is the initialisation of a variable; a variable cannot be accessed until it has been initialised.

All of which still doesn't answer the question: let or const for array variables? In either case, the array variable may not be declared twice within a given scope, but whether an array variable is declared using let or const, array elements may be added, removed or have their value changed. What we have to remember here is that an array is essentially an object (albeit a specialised kind of object), and that the array variable we declare is a reference to that object.

The real difference between using let and const to declare an array is that if you declare an array variable using let, JavaScript will allow you to reassign that variable name to another object, whereas if you declare the array variable using const, that will not be allowed. If you want to ensure that your array variable names are not inadvertently reassigned, use const; Apart from that, there is nothing actually stopping you from using let. An couple of examples should serve to clarify the situation. This code results in an error:

const myArray = [1,2,3,4,5];
const anotherArray = [6,7,8,9,10];
myArray = anotherArray;

This results in the following error message:

Uncaught TypeError: invalid assignment to const 'myArray'

This code, on the other hand, will not trigger an error

let myArray = [1,2,3,4,5];
const anotherArray = [6,7,8,9,10];
myArray = anotherArray;
console.log(myArray); // Array(5) [6,7,8,9,10]

We will not make a recommendation here on whether you should use let or const when declaring array variables, other than to say that unless you foresee the need to reassign an array variable name, there is no particular reason not to use const. As with many aspects of JavaScript programming, opinions on this subject differ.

* A shallow copy is a copy of an object that contains all of the values in the original object. However, if any of these values are references to other objects, only the reference addresses are copied. A deep copy also contains all of the values in the original object, but if any of these values are references to other objects, both the referring object and the objects to which it refers are copied.

Adding array elements

Adding an element to an array can be done in several ways. One way of adding an element to an array is to use simple assignment. For example:

const myArray = ["Jan","Feb","Mar"];
myArray[3] = "Apr";
console.log(myArray); // Array(4) ["Jan","Feb","Mar","Apr"]

The above code adds a new array element to the array at a specific array index, increasing the length of the array by one. Using this method of adding an element to the end of the array relies on knowing how many items are already in the array - or rather, knowing the array index of the last item in the array, since there could be one or more empty slots within the array. We could of course use the array's length property as the array index for the new element, since this is guaranteed to be one greater than the last array index:

const myArray = ["Jan","Feb","Mar"];
myArray[myArray.length] = "Apr";
console.log(myArray); // Array(4) ["Jan","Feb","Mar","Apr"]

It is also possible to add a new element to an array with an index value that is greater than the length property. This will result in the length property being updated, but it will also introduce gaps into the array. Unless this is a specific requirement of your code for some reason, you should probably avoid doing so.

If we simply want to add one or more array elements to the end of an array, a far more elegant way of achieving this is to use the push method, which adds any elements passed to it as parameters to the end of the array (essentially treating the array as a stack), and returns the new array length. For example:

const myArray = ["Jan","Feb"];
let newLength = myArray.push("Mar");
console.log(newLength); // 3
console.log(myArray); // Array(3) ["Jan","Feb","Mar"]

const myArray = [1,2,3];
let newLength = myArray.push(4,5,6);
console.log(newLength); // 6
console.log(myArray); // Array(6) [1,2,3,4,5,6]

If we want to add elements to the beginning of an array, we can use the unshift method. Like push, the unshift method returns the new array length once it has added the elements passed to it as parameters to the beginning of the array. For example:

const myArray = ["Mar"];
let newLength = myArray.unshift("Jan","Feb");
console.log(newLength); // 3
console.log(myArray); // Array(3) ["Jan","Feb","Mar"]

const myArray = [4,5,6];
let newLength = myArray.unshift(1,2,3);
console.log(newLength); // 6
console.log(myArray); // Array(6) [1,2,3,4,5,6]

The unshift method requires more processing time than the push method because as well as updating the length property it must re-index the existing array elements, which will be displaced by the new array elements being added to the start of the array.

We might also want to add elements elsewhere within the array, rather than at the end or at the beginning of the array. We can do this using the splice method, which inserts one or more new array elements into the array at the specified index position (it can also optionally remove one or more elements from the array, starting from the same position). The following example inserts two array elements at index 2 (the third position in the array):

const myArray = [1,2,5,6];
let newLength = myArray.splice(2,0,3,4);
console.log(myArray); // Array(6) [1,2,3,4,5,6]

The first parameter taken by the splice method is the index at which elements should be inserted and/or deleted. The second parameter specifies how many (if any) elements should be deleted, and all additional parameters specify values to be inserted in the array, starting at the specified index. Like unshift, the splice method will not only update the length property, but also re-index any array elements displaced by the insertion of new elements into the array.

We may want, on occasion, to create an array with a fixed number of elements without knowing precisely what values each element will take. We can create the array and populate it with "placeholder" values in one statement by using the fill method. The following example creates an array with five elements, and sets each array element to zero:

const myArray = Array(5).fill(0);
console.log(myArray); // Array(5) [0,0,0,0,0]

You can also use optional start and end parameters with the fill method. The range of array element from index start up to (but not including) index end are replaced with the specified static value. For example:

const myArray = [1,2,3,4,5,6,7,8,9];
myArray.fill(-1,3,6);
console.log(myArray); // Array(10) [1,2,3,-1,-1,-1,7,8,9]

Removing array elements

Removing an element from the end of an array can be done in a couple of ways. If you just want to remove the last element in the array without first retrieving its value, you could simply decrement the array length by one:

const myArray = ["dog","cat","rabbit","guinea pig"];
--myArray.length;
console.log(myArray); // Array(3) ["dog","cat","rabbit"]

In fact, you could delete any number of array elements from the end of the array in this way, or even clear the array by setting its length property to zero.

Sometimes, we want to retrieve the value of the last element in an array as well as removing it from the end of the array. In this case, we use the pop method, which removes the last element of an array as if the array were a stack, and returns its value:

const myArray = ["dog","cat","rabbit","guinea pig"];
let popped = myArray.pop;
console.log(popped); // guinea pig
console.log(myArray); // Array(3) ["dog","cat","rabbit"]

Removing an item from the start of the array is just as easy. We can use the shift method, which removes the first element of the array and returns its value:

const myArray = ["dog","cat","rabbit","guinea pig"];
let shifted = myArray.shift;
console.log(shifted); // dog
console.log(myArray); // Array(3) ["cat","rabbit","guinea pig"]

If we want to remove one or items from a specific location within an array, we can do this using the splice method, which we have already seen in the context of inserting array elements at a specific location. The position within the array from which the elements are removed, and the number of elements removed from the array, are passed to the splice method as its first two arguments. In fact, unless we are also inserting elements into the array, these will be the only two arguments used.

The splice method returns a new array containing the elements removed from the target array, and updates the length property of the target array. In the following example, two array elements are removed, starting at index 1:

const myArray = ["dog","cat","rabbit","guinea pig"];
const removed = myArray.splice(1,2);
console.log(removed); // Array ["cat","rabbit"]
console.log(myArray); // Array ["dog","guinea pig"]

Note that, as with methods that add elements to the beginning of an array or somewhere within the array, elements that remove elements from the beginning of an array or somewhere within the array must re-index any elements that are displaced by the operation. They are thus more processor intensive than methods that add or remove elements at the end of an array.

Accessing array elements

We often want to access one or more elements within an array without removing them or changing their value. For example, we might want to find the position of a particular item within an array, find the value of the item at a given position in an array, check for duplicate values within an array, or search an array to see whether or not it contains a particular value. We might also wish to cycle through the array and display some or all of its contents.

Let's suppose that we just want to display the values stored in each array element, one after the other. We could do this in several ways, each of which involves looping through the array. For example, we could simply loop over the array indexes:

const primes = [2,3,5,7];
for (let i = 0; i < primes.length; i++) {
  console.log(primes[i]);
}
// 2
// 3
// 5
// 7

The following code does exactly the same thing, but this time we use the values method to return an iterator object - essentially an array containing the array object's iterable values - which we can then access using a loop:

const primes = [2,3,5,7];
const iterator = primes.values;
for (const value of iterator) {
  console.log(value);
}
// 2
// 3
// 5
// 7

We can retrieve the value of an array element using its index within the array. For example, suppose I have an array containing all of the prime numbers between 0 and 20, and I want to extract the last prime number in the sequence. I could do something like this:

const primes = [2,3,5,7,11,13,17,19];
let len = primes.length;
let biggestPrime = primes[len-1];
console.log(biggestPrime); // 19

This is not particularly useful, however, if we don't know the position of a particular item within an array. We may not even be certain whether or not the array actually contains the item we are interested in. We can display a list of array elements and their indices easily enough by invoking the entries method. This method works like the values method except that the returned iterator object is an array that contains both the array object's iterable values and the array index associated with each value:

const primes = [2,3,5,7];
const iterator = primes.entries;
for (const value of iterator) {
  console.log(value);
}
// Array [0,2]
// Array [1,3]
// Array [2,5]
// Array [3,7]

Note that we could also use the keys method, which returns an iterator object that contains the indices for each value in the array, to extract the same basic information:

const primes = [2,3,5,7];
const iterator = primes.keys();
for (const value of iterator) {
  console.log(value, primes[value]);
}
// 0 2
// 1 3
// 2 5
// 3 7

As mentioned above, we are often interested in finding out whether a particular value is stored in an array. Suppose for example, we have an array that contains all of the prime numbers between 0 and 100. We might want to check whether a particular number in that range was a prime number or not. The HTML code below creates a web page that allows the user to enter a number between 0 and 100, The user can then click on a button to see whether or not the number they have entered is a prime number. Here is the code:

<!doctype html>
<html lang="en">

  <head>
    <meta charset="utf-8">
    <title>JavaScript Demo 25</title>
    <style>
      .center { text-align: center; }
      button, input { width: 5em; }
    </style>
    <script>
      const primes = [2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97];
      function numberCheck () {
        document.getElementById("outcome").innerHTML = "";
        let num = parseInt(document.getElementById("inputNum").value);
        if (num < 0 || num > 100) {
          document.getElementById("outcome").innerHTML = "The number you entered is outside the specified range.";
          return;
        }
        if (primes.includes(num)) {
          document.getElementById("outcome").innerHTML = "The number you entered is prime.";
        }
        else {
          document.getElementById("outcome").innerHTML = "The number you entered is not prime.";
        }
      }
    </script>
  </head>

  <body>
    <div class="center">
      <h1>Prime Number Checker</h1>
      <p><strong>Enter a number between 0 and 100:</strong></p>
      <p>
        <label>Number: </label><input type="number" id="inputNum" min="0" max="100">
        <button onclick="numberCheck()">Check</button>
      </p>
      <p id="outcome"></p>
    </div>
  </body>
</html>

Copy and paste this code into a new file in your HTML editor, save the file as javascript-demo-25.html, open the file in a web browser, enter a number between 0 and 100 into the input field, and click on the "Check" button. Depending on the number you enter, you should see something like this:


The script checks whether the number entered is a prime number

The script checks whether the number entered is a prime number


Merging arrays

Can we merge two JavaScript arrays? The concat method would at first glance appear to do just that. It allows us to concatenate (merge) two or more arrays, or add several new values to an array, in a single operation. What we are actually doing, however, is concatenating the contents of two or more arrays in order to create a new array. The original arrays remain unaltered. The following code demonstrates the use of the concat method:

const associates = ["D Jones","F Kruger","D Darko"];
const committee = ["J Fonda","P Perfect","D Day"];
const mailingList = associates.concat(committee, "L Furlevver");
console.log(mailingList, associates, committee);
// Array(7) [ "D Jones", "F Kruger", "D Darko", "J Fonda", "P Perfect", "D Day", "L Furlevver" ]
// Array(3) [ "D Jones", "F Kruger", "D Darko" ]
// Array(3) [ "J Fonda", "P Perfect", "D Day" ]

The above code concatenates the committee array and the string variable "L Furlevver" with the array associates by calling the concat method on the associates array and passing the committee array and the string variable "L Furlevver" to it as parameters. As you can see from the console output, the original arrays have not been changed in any way.

Note also the order in which the array variables appear in the newly created array. As you might expect, the array variables in the associates array on which the concat method is called appear first, followed by those in the committee array, followed by the string variable "L Furlevver". The order in which the parameters are passed to the concat method is thus preserved.

In theory, there is no limit to the number of parameters that can be passed to the concat method. They can also be of different types. For example:

const arr1 = [1, 2, 3];
const arr2 = ["a","b","c"];
const arr3 = [4.5, 5.5, 6.5];
const arr4 = arr1.concat(arr2, "fee", "fie", "foe", arr3);
console.log(arr4);
// Array(12) [ 1, 2, 3, "a", "b", "c", "fee", "fie", "foe", 4.5, … ]

Note that parameters for concat are optional. If no arguments are passed to the concat method, it returns a shallow copy (see the note at the end of Array method reference below) of the array on which it is called. The concat method also does not recurse into nested (multi-dimensional) array arguments. The new array returned instead contains an object reference to the nested array. To clarify, elements from the arrays passed to concat as arguments are copied into the new array as follows:

From the above, we can infer that operations carried out on a new array created with concat will not affect the contents of any arrays passed to it as arguments (and vice versa) unless the operations are carried out on elements that are object references. Consider the following code:

const arr1 = [1, 2, 3];
const arr2 = [4, 5, 6];
const arr3 = [arr2, 7, 8, 9]
const arr4 = arr1.concat(arr3);
console.log(arr4); // Array(7) [ 1, 2, 3, (3) […], 7, 8, 9 ]
arr1.push(0);
console.log(arr1); // Array(4) [ 1, 2, 3, 0 ]
console.log(arr4); // Array(7) [ 1, 2, 3, (3) […], 7, 8, 9 ]

As we can see from the console output, adding an element to array variable arr1 does not affect array variable arr4. , because the value of each element in arr1 is copied into arr4 by the concat method, as opposed to a reference to arr1. By contrast, let's see what happens if we make changes to array variable arr2:

const arr1 = [1, 2, 3];
const arr2 = [4, 5, 6];
const arr3 = [arr2, 7, 8, 9]
const arr4 = arr1.concat(arr3);
arr2.push(7);
console.log(arr2); // Array(4) [ 4, 5, 6, 7 ]
console.log(arr4[3]); // Array(4) [ 4, 5, 6, 7 ]

The first three elements in arr4 are the three values copied from arr1, but the fourth element (arr4[3]) will be a reference to array variable arr2. As you can see from the console output, any changes we make to the referenced array will also affect the new array. This works in both directions, as demonstrated by the following code:

const arr1 = [1, 2, 3];
const arr2 = [4, 5, 6];
const arr3 = [arr2, 7, 8, 9]
const arr4 = arr1.concat(arr3);
arr4[3].push(11);
console.log(arr4[3]); // Array(4) [ 4, 5, 6, 11 ]
console.log(arr2); // Array(4) [ 4, 5, 6, 11 ]

Reordering arrays

As mentioned at the beginning of this article, arrays can be used to create linear data structures such as lists, queues and stacks. For lists in particular, the ability to reorder the contents of an array is particularly useful. JavaScript provides two re-ordering methods for arrays - sort and reverse. The purpose of these methods is fairly self-explanatory. The sort method compares the values of the elements in the array according to some criterion and reorders them accordingly. The reverse method reverses the existing order of the elements in the array.

We'll look at the sort method first. When used without the optional comparison function argument (see below), the sort method converts numeric arguments to strings in order to sort them alphanumerically (as sequences of UTF-16 code unit values) in ascending order. This is demonstrated by the following code:

const arr1 = [10, 9, 6, 7, 1, 5, 2, 0];
console.log(arr1);
console.log(arr1.sort());
// Array(8) [ 10, 9, 6, 7, 1, 5, 2, 0 ]
// Array(8) [ 0, 1, 10, 2, 5, 6, 7, 9 ]

At first glance, the sort method appears to have sorted our numerical array correctly, but note where the value "10" appears in the sorted array. Since this is the largest value in the unsorted array, we would expect to see it appear as the last value in the sorted array. Remember, however, that when used without parameters, sort converts numeric values to strings before it sorts them. It therefore sees the array as: ["10", "9", "6", "7", "1", "5", "2", "0"]. In order to sort numerical values correctly, we can use a comparison function which will replace the default string comparison:

const arr1 = [10, 9, 7, 1, 5];

function numCompare(a, b) { return a - b; }

console.log(arr1); // Array(5) [ 10, 9, 7, 1, 5 ]
console.log(arr1.sort()); // Array(5) [ 1, 10, 5, 7, 9 ]
console.log(arr1.sort(numCompare)); // Array(5) [ 1, 5, 7, 9, 10 ]

A comparison function takes two array elements as its arguments, which well call element1 and element2. If both elements have the same value, the function returns zero. If the value of element1 is greater than that of element2, a positive value is returned. If element1 is greater than element2, a negative value is returned. The simplest way to implement this functionality is to subtract the value of element2 from that of element1, as we have done in our code. Note that we can also specify the function inline, like this:

const arr1 = [10, 9, 7, 1, 5];

console.log(arr1); // Array(5) [ 10, 9, 7, 1, 5 ]
console.log(arr1.sort()); // Array(5) [ 1, 10, 5, 7, 9 ]
console.log(arr1.sort(function numCompare(a, b) { return a-b; }));
// Array(5) [ 1, 5, 7, 9, 10 ]

If you are likely to use the comparison function on a number of different arrays, it would make more sense to define the function separately, although following the publication of ECMAScript standard ES2015, there is now a far more compact way to call a comparison function inline using arrow notation. Here is an example of its use:

const arr1 = [10, 9, 7, 1, 5];
console.log(arr1.sort((a, b) => a - b));
// Array(5) [ 1, 5, 7, 9, 10 ]

A similar problem arises when we want to sort an array of text string values alphabetically. All strings start with an uppercase character will appear before any strings that start with a lowercase character, which in most cases is not what we want. Again, we need to use a comparison function. One possible solution is to convert the string values to all lowercase (or all uppercase) before carrying out the comparison, as demonstrated by the following code:

const names = ["Eddie", "Sue", "George", "Alan", "james"];

function strCompare(a, b) {
  a = a.toLowerCase();
  b = b.toLowerCase();
  if (a > b) return 1;
  if (a < b) return -1;
  return 0;
}
console.log(names.sort());
// Array(5) [ "Alan", "Eddie", "George", "Sue", "james" ]
console.log(names.sort(strCompare));
// Array(5) [ "Alan", "Eddie", "George", "james", "Sue" ]

Another problem can potentially arise when sorting arrays of strings containing non-ASCII characters. French alone uses many characters that have an acute, grave or circumflex accent. In addition to the plain old letter "e", for example, we might see e acute (é), e grave (è), or e circumflex (ê). When dealing with texts written in a language other than English, therefore, use the localCompare function:

const myVocabulary = ["père", "çava", "potage", "couche", "école"];

function vocabSort(a, b) {
  return a.localeCompare(b);
}

console.log(myVocabulary.sort());
// Array(5) [ "couche", "potage", "père", "çava", "école" ]
console.log(myVocabulary.sort(vocabSort));
// Array(5) [ "çava", "couche", "école", "père", "potage" ]

It is also possible to sort an array of objects by comparing the value of a specific property. This can be particularly useful if we want to look at the same data according to different criteria. The HTML code below creates a web page that allows the user to look at a list of students in a class, either listed in alphabetical order or according to their examination scores. Note that the array is already sorted by name in alphabetical order. The page allows us to toggle between the two views. Here is the code:

<!doctype html>
<html lang="en">

  <head>
    <meta charset="utf-8">
    <title>JavaScript Demo 26</title>
    <style>
        .center { text-align: center; }
        button, input { width: 10em; }
        table, th, td { border: 1px solid; margin: auto; }
        tr td:first-child {text-align: left; padding: 0 1em; }
    </style>
    <script>
      const students = [
        { name: "Anderson, N", score: 51 },
        { name: "Beckham, D", score: 31 },
        { name: "Dean, P", score: 67 },
        { name: "Einstein, A", score: 99 },
        { name: "Foster, R", score: 95 },
        { name: "Finn, M", score: 39 },
        { name: "Jonas, J", score: 29 },
        { name: "Miller, G", score: 75 },
        { name: "Scott, G", score: 67 },
        { name: "Wells, C", score: 98 }
      ];

      function createList() {
        document.getElementById("students").innerHTML = "";
        let studentTable = "<table><tr><th>Name</th><th>Exam score</th></tr>";
        for(let i = 0; i < students.length; i++) {
          studentTable += ("<tr><td >" + students[i].name + "</td><td>" + students[i].score + "</td></tr>");
        }
        studentTable += "</table>";
        document.getElementById("students").innerHTML = studentTable;
      }

      function byName(a, b) {
        if (a.name > b.name) return 1;
        if (a.name < b.name) return -1;
        return 0;
      }

      function byScore(a, b) {
        if (a.score > b.score) return 1;
        if (a.score < b.score) return -1;
        return 0;
      }

      function nameView() {
        students.sort(byName);
        createList();
      }

      function scoreView() {
        students.sort(byScore);
        createList();
      }
    </script>
  </head>

  <body onload="nameView()">
    <div class="center">
      <h1>Class of 2022</h1>
      <button onclick="nameView()">Sort by name</button>
      <br><br>
      <button onclick="scoreView()">Sort by score</button>
      <br>
      <p><strong>Select a sort criterion:</strong></p>
      <div id="students"></div>
    </div>
  </body>
</html>

Copy and paste this code into a new file in your HTML editor, save the file as javascript-demo-26.html, open the file in a web browser, and click on the "Sort by name" and "Sort by score" buttons a few times to see what happens. By default, the list is sorted alphabetically by name when the page loads. If you click on the "Sort by score" button, you should see something like this:


The script enables the user to sort the list alphabetically, or according to student scores

The script enables the user to sort the list alphabetically, or according to student scores


If two students have the same score, the order in which they appear in the list when it is sorted by score should be the same order in which they appear in the array on which the sort is called. This behaviour is referred to as sort stability, and is mandated by the tenth edition of the ECMA standard (ES2019), which at the time of writing is the most recent version.

Note that the sort method sorts the array in place, i.e. it sorts the array elements within the array on which it is called, and does not create a copy of the array. The return value is the sorted array. Note also that undefined elements are always sorted to the end of the array, as the following code demonstrates:

let a, b, c=0;
const someArray = [a, 1, 7, 5, b, 11, 3, c];

console.log(someArray);
// Array(8) [ undefined, 1, 7, 5, undefined, 11, 3, 0 ]
console.log(someArray.sort());
// Array(8) [ 0, 1, 11, 3, 5, 7, undefined, undefined ]

The other reordering method we will look at briefly is the reverse method, which pretty much does exactly what its name suggests, i.e. reverse the order of the array elements:

const pets = ["Cat", "Dog", "Rabbit", "Gerbil"];

console.log(pets); // Array(4) [ "Cat", "Dog", "Rabbit", "Gerbil" ]
pets.reverse();
console.log(pets); // Array(4) [ "Gerbil", "Rabbit", "Dog", "Cat" ]

Like the sort method, reverse reorders the elements of the array in place, and does not create a copy of the array. The return value is the reversed array.

Cloning arrays

When we create an array variable, the variable itself is actually a reference to the location of the array in memory. This has consequences that may not be immediately obvious. We can, for example, create two identical arrays, as demonstrated by the code below. Note, however, what happens when we apply the equality operator:

const arr1 = [1, 2, 3, 4];
const arr2 = [1, 2, 3, 4];

console.log(arr1 == arr2); // false

Why is arr1 not equal to arr2? Because these variables are references to two separate arrays, each of which exists at a unique location in memory. If we were to do an element-by-element comparison of the array elements themselves, the result would be more in line with what we might expect.

If we wanted to clone (i.e. duplicate) an array, we might try something like the following:

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

arr2 = arr1;
console.log(arr2 == arr1); // true

So have we successfully duplicated arr1? Unfortunately, no. Bearing in mind that an array variable is a reference to a location in memory, then the fact that arr1 is equal to arr2 simply means that arr1 and arr2 are both pointing to the same array. All we have done, essentially, is create two references to the same object, as demonstrated by this code:

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

arr2 = arr1;
arr2.pop();
console.log(arr2); // Array(3) [ 1, 2, 3 ]
console.log(arr1); // Array(3) [ 1, 2, 3 ]

We could of course create an exact copy of an existing array by duplicating the original array declaration using a different array variable name, as we saw above. This can result in some fairly cumbersome code, however, particularly if the original array element has a large number of elements. There is also a more compelling reason to find an alternative means of cloning an array, however, which is that we might want to take a snapshot of the array at a particular point in time.

Let's assume, for example, that we have an array that is being processed in various ways. We may be adding or removing elements, or changing the value of one or more elements. We may also be reordering the array in various ways. If we want to capture the state of the array at some point during all this processing, it would be useful if we could find a simple way to do so.

There are, in fact, several relatively easy ways to clone an array. We'll look at two of them here. The first involves the use of the slice method. We call slice, without any arguments (or with zero as its only argument), on the array to be cloned. When used without arguments, slice returns a shallow copy (see the note at the end of Array method reference below) of the array on which it is called, so any array elements that are references to objects will point to the same objects as their counterparts in the original array. The original array is not modified in any way. Here is an example:

const arr1 = [1, 2, 3, 4];
const arr2 = arr1.slice();

arr1.pop();
console.log(arr1); // Array(3) [ 1, 2, 3 ]
console.log(arr2); // Array(4) [ 1, 2, 3, 4 ]
console.log(arr2 == arr1); // false

Notice that once we have "cloned" an array in this fashion, any operations carried out on it will not affect the clone. Notice also the two array variables (arr1 and arr2) point to different locations in memory - they are therefore not equal. We can achieve exactly the same end result using the concat method in a similar way, either with no arguments or using an empty array as its only argument:

const arr1 = [1, 2, 3, 4];
const arr2 = arr1.concat([]);

arr1.pop();
console.log(arr1); // Array(3) [ 1, 2, 3 ]
console.log(arr2); // Array(4) [ 1, 2, 3, 4 ]
console.log(arr2 == arr1); // false

As we mentioned above, the cloning methods described so far create a shallow copy of the array, which means that elements in the cloned array that are references to objects still point to the same objects - the objects themselves have not been duplicated. There may however be occasions when we want to make a deep copy of an array.

A deep copy contains all of the values in the original array, but if any of these values are references to other objects, the referenced objects are also copied. The references themselves will be different to the references in the original array, because they will be pointing to different objects. So how do we do this? To some extent, it depends on the nature of the objects referenced by the array variables. Those objects may contain references to other objects. They may even be arrays themselves, some elements of which are references to more deeply nested objects.

Creating a deep copy of an array that contains references to objects often involves using workarounds and libraries. Depending on the level of nesting involved and the nature of any objects referenced, It may be possible (for example) to use a solution that utilises JavaScript Object Notation (JSON). Such a solution will not work in every situation, however.

The JavaScript API used by all recent versions of Google Chrome, Mozilla Firefox and Microsoft Edge now includes the structuredClone method which will make a deep copy of an array passed to it as a parameter. The following code demonstrates its use:

arr1 = [1, 2, 3];
arr2 = [arr1, 3, 4, 5];
arr3 = structuredClone( arr2 )
console.log( arr2[0] ); // Array(3) [ 1, 2, 3 ]
console.log( arr3[0] ); // Array(3) [ 1, 2, 3 ]
arr1.pop();
console.log( arr2[0] ); // Array [ 1, 2 ]
console.log( arr3[0] ); // Array(3) [ 1, 2, 3 ]

The first element in arr2 is a reference to arr1, so any change to arr1 will be reflected in the output for console.log( arr2[0] ). The first element of arr3, on the other hand, is a reference to a copy of arr1, so any changes to arr1 will not be reflected in the output for console.log( arr3[0] ). When an array is deep copied using structuredClone, the copied array is a faithful reproduction of the original array including any objects it refers to (the object references themselves will of course change, since they are now pointing at copies of the original objects rather than the original objects themselves).

There are one or two caveats to consider when using structuredClone. First of all, it will not work with older browsers, including Microsoft Internet Explorer. If you really need to accomodate these older browsers you should consider an alternative approach. Secondly, using structuredClone with a class instance returns a plain object - the class object’s prototype chain is discarded. A similar thing happens with functions - they too are quietly discarded (we'll be looking at JavaScript classes and functions elsewhere). Other object types not compatible with structuredClone include error objects and DOM nodes, which will cause structuredClone to throw an exception.

Multidimensional arrays

As with other programming languages, a multidimensional array in JavaScript can best be described as an array of arrays, i.e. an array in which the array elements themselves are arrays. Depending on the number of dimensions in our multi-dimensional array, the elements of the arrays referenced by both the top-level array and lower-level arrays may themselves be arrays.

Multi-dimensional arrays are extremely useful in certain situations. Tabular data (i.e. data arranged in rows and columns) can be represented using a two dimensional array. The array then becomes an array of arrays. If we think about two-dimensional tables in database terms, each array element in the top-level array could represent a record. Each record consists of a second-level array whose elements are the field data items.

We saw an example of how arrays might be used to store and manipulate the tabular data used to construct a football league table in the article "Working with Strings" in this section. In that example, we declared the data for each field in a separate array and then used the array data to construct an HTML table. Here is the relevant block of code:

let teams = ["Manchester City", "Liverpool", "Chelsea", "Tottenham Hotspur", "Arsenal", "Manchester United", "Wolverhampton Wanderers", "Everton", "Leicester City", "West Ham United", "Watford", "Crystal Palace", "Newcastle United", "Bournemouth", "Burnley", "Southampton", "Brighton & Hove Albion", "Cardiff City", "Fulham", "Huddersfield Town"];
let played = [38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38];
let won = [32, 30, 21, 23, 21, 19, 16, 15, 15, 15, 14, 14, 12, 13, 11, 9, 9, 10, 7, 3];
let drawn = [2, 7, 9, 2, 7, 9, 9, 9, 7, 7, 8, 7, 9, 6, 7, 12, 9, 4, 5, 7];
let lost = [4, 1, 8, 13, 10, 10, 13, 14, 16, 16, 16, 17, 17, 19, 20, 17, 20, 24, 26, 28];
let goalsFor = [95, 89, 63, 67, 73, 65, 47, 54, 51, 52, 52, 51, 42, 56, 45, 45, 35, 34, 34, 22];
let goalsAgainst = [23, 22, 39, 39, 51, 54, 46, 46, 48, 55, 59, 53, 48, 70, 68, 65, 60, 69, 81, 76];
let goalDifference = [72, 67, 24, 28, 22, 11, 1, 8, 3, -3, -7, -2, -6, -14, -23, -20, -25, -35, -47, -54];
let points = [98, 97, 72, 71, 70, 66, 57, 54, 52, 52, 50, 49, 45, 45, 40, 39, 36, 34, 26, 16];

This works, but we have essentially used a number of one-dimensional arrays to store the data rather than creating a true two-dimensional array. There are two ways in which we could create a two-dimensional array to hold the same data. The first might look like this:

let leagueTable = [["Manchester City", "Liverpool", "Chelsea", "Tottenham Hotspur", "Arsenal", "Manchester United", "Wolverhampton Wanderers", "Everton", "Leicester City", "West Ham United", "Watford", "Crystal Palace", "Newcastle United", "Bournemouth", "Burnley", "Southampton", "Brighton & Hove Albion", "Cardiff City", "Fulham", "Huddersfield Town"], [38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38], [32, 30, 21, 23, 21, 19, 16, 15, 15, 15, 14, 14, 12, 13, 11, 9, 9, 10, 7, 3], [2, 7, 9, 2, 7, 9, 9, 9, 7, 7, 8, 7, 9, 6, 7, 12, 9, 4, 5, 7], [4, 1, 8, 13, 10, 10, 13, 14, 16, 16, 16, 17, 17, 19, 20, 17, 20, 24, 26, 28], [95, 89, 63, 67, 73, 65, 47, 54, 51, 52, 52, 51, 42, 56, 45, 45, 35, 34, 34, 22], [23, 22, 39, 39, 51, 54, 46, 46, 48, 55, 59, 53, 48, 70, 68, 65, 60, 69, 81, 76], [72, 67, 24, 28, 22, 11, 1, 8, 3, -3, -7, -2, -6, -14, -23, -20, -25, -35, -47, -54], [98, 97, 72, 71, 70, 66, 57, 54, 52, 52, 50, 49, 45, 45, 40, 39, 36, 34, 26, 16]];

Or we could retain our original array declarations and do this instead:

let leagueTable = [ teams, played, won, drawn, lost, goalsFor, goalsAgainst, goalDifference, points ];

Both of these declarations result in two-dimensional arrays that contain the same data, but the second could perhaps be considered better from the point of view of maintainability, and readable code, since it retains the original array names. Either way, we can use index notation to access all of the elements in the two-dimensional array. Here is an alternative version of our football league web page:

<!doctype html>
<html lang="en">

  <head>
    <meta charset="utf-8">
    <title>JavaScript Demo 27</title>
    <style>
      th, td {
        border: 1px solid grey;
        padding: 0.25em 0.5em;
        text-align: center;
        font-size: smaller;
      }
      table {
        margin: auto;
        border-collapse: collapse;
      }
      .center { text-align: center; }
      tr td:nth-child(2) { text-align: left; }
    </style>
    <script>
      let leagueTable = [["Manchester City", "Liverpool", "Chelsea", "Tottenham Hotspur", "Arsenal", "Manchester United", "Wolverhampton Wanderers", "Everton", "Leicester City", "West Ham United", "Watford", "Crystal Palace", "Newcastle United", "Bournemouth", "Burnley", "Southampton", "Brighton & Hove Albion", "Cardiff City", "Fulham", "Huddersfield Town"], [38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38], [32, 30, 21, 23, 21, 19, 16, 15, 15, 15, 14, 14, 12, 13, 11, 9, 9, 10, 7, 3], [2, 7, 9, 2, 7, 9, 9, 9, 7, 7, 8, 7, 9, 6, 7, 12, 9, 4, 5, 7], [4, 1, 8, 13, 10, 10, 13, 14, 16, 16, 16, 17, 17, 19, 20, 17, 20, 24, 26, 28], [95, 89, 63, 67, 73, 65, 47, 54, 51, 52, 52, 51, 42, 56, 45, 45, 35, 34, 34, 22], [23, 22, 39, 39, 51, 54, 46, 46, 48, 55, 59, 53, 48, 70, 68, 65, 60, 69, 81, 76], [72, 67, 24, 28, 22, 11, 1, 8, 3, -3, -7, -2, -6, -14, -23, -20, -25, -35, -47, -54], [98, 97, 72, 71, 70, 66, 57, 54, 52, 52, 50, 49, 45, 45, 40, 39, 36, 34, 26, 16]];

      let leagueTableHTML = ""

      function displayTable () {
        leagueTableHTML += "<table><caption><h2>2018/2019 Season</h2></caption>\ <thead><tr><th>#</th><th>Team</th><th>Pl</th><th>W</th><th>D</th>\ <th>L</th><th>F</th><th>A</th><th>GD</th><th>Pts</th></tr></thead><tbody>";
        let i, j = 8;
        for (i = 0; i < leagueTable[0].length; i++ ) {
          leagueTableHTML += "<tr><td>" + (i + 1) + "</td>";
          for (j = 0; j < leagueTable.length; j++ ) {
            leagueTableHTML += "<td>" + leagueTable[j][i] + "</td>";
          }
          leagueTableHTML += "</tr>";
        }
        leagueTableHTML += "<tfoot><tr><td colspan='10'>\
        <strong>Key:</strong><br><br>\
        <strong>Pl</strong> = Played\
        <strong>W</strong> = Won\
        <strong>D</strong> = Drawn\
        <strong>L</strong> = Lost<br>\
        <strong>F</strong> = For\
        <strong>A</strong> = Against\
        <strong>GD</strong> = Goal difference\
        <strong>Pts</strong> = Points<br><br>\
        </td></tr></tfoot></table>";
        document.getElementById("leagueTable").innerHTML = leagueTableHTML;
      }
    </script>
  </head>

  <body onload="displayTable()">
    <div class="center">
      <h1>English Premier League</h1>
      <div id="leagueTable"></div>
    </div>
  </body>
</html>

This example is somewhat contrived, but it demonstrates how a two-dimensional array can be used. The displayTable() function that generates the HTML that displays the table data in our web page is a little more concise, thanks to the fact that we can use indices in nested for loops to access the data we need using a single two-dimensional array rather than several one-dimensional arrays.

In theory, there is no limit to the number of dimensions an array can have. We can have arrays of arrays of arrays . . . well, you get the idea. In practice, two-dimensional arrays will fulfil most requirements. You may have noticed that, in order to access an individual element in a multi-dimensional array, we need to use two or more indices, depending on the level within the array at which the element is nested. Suppose we have a two-dimensional array that stores the contents of a 3 x 3 number matrix, and let's say that we want to retrieve the number stored in the second column and second row of the matrix:

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

console.log( matrix[1][1] ); // 5

Note that we have spread the inner array declarations over three lines in order to make the code more readable - it allows us to visualise the matrix in terms of its rows and columns. The expression matrix[1][1] thus references the item located in the second row, and in the second column.

As you can see, multi-dimensional arrays are very handy when we want to store either tabular data or matrices. Those of you interested in developing computer games may have already encountered matrices, since they are often used to store position coordinates for game sprites and other graphical objects.

Searching arrays

Searching an array is not usually a requirement if the array in question only contains a few elements. For large arrays, however we often need to answer specific questions about the array. Does the array, for example, contain a particular value, and if so, how many instances of the value does it contain? We might want to find the position within an array of a particular value. We might even want to display a list of elements in the array that meet specific criteria.

JavaScript provides a number of methods that allow us to determine the answer to such questions. The return value will depend on the method used to search an array - it could be a Boolean value, an array value, an index number, or a new array. Note, however, that none of the methods used to search an array alter the contents of the original array.

We'll deal first with the question as to whether or not an array contains a particular value. We can do this quite easily using the includes method. Here is an example:

const numbers = [1, 5, 7, 11, 21, 33, 35, 66];

console.log( numbers.includes( 15 )); // false
console.log( numbers.includes( 33 )); // true

Note, however, that the includes method does not search the array recursively. Suppose, for example, we are looking for the number 33 as previously. Let's further suppose that the number 33 is not one of the top-level array elements in our numbers array, but that one of the elements in the array is another array of numbers that does contain the number 33:

const numbers = [1, 5, 7, [11, 21, 33, 35, 66]];

console.log( numbers.includes( 33 )); // false

If we want to find out if a given value exists withing a multi-dimensional array, we could write a recursive function that uses the includes method, as demonstrated by the following code:

const numbers = [1, 5, 7, [11, 21, 33, [39, 67, 101]]];

function deepInclude (arr, element) {
  if (arr.includes(element)) {
    return true;
  }
  else {
    for (i = 0; i < arr.length; i++ ) {
      if (Array.isArray(arr[i])) {
        return deepInclude(arr[i], element);
      }
    }
  }
  return false;
}

console.log( deepInclude(numbers, 5)); // true
console.log( deepInclude(numbers, 9)); // false
console.log( deepInclude(numbers, 11)); // true
console.log( deepInclude(numbers, 34)); // false
console.log( deepInclude(numbers, 67)); // true

Sometimes we want to know if a value exists within an array and the position within the array at which it occurs, if indeed it does occur. There are two methods we can call on here. The indexOf method returns the index number of the first instance found in the array, or -1 if it is not present. The lastIndexOf method returns the index number of the last instance found, or -1 if it is missing. Here is an example:

const numbers = [1, 5, 7, 13, 7];

console.log( numbers.indexOf( 3 ) ); // -1
console.log( numbers.indexOf( 7 ) ); // 2
console.log( numbers.lastIndexOf( 7 ) ); // 4

Like the includes method, neither indexOf or lastIndexOf search an array recursively. We leave it as an exercise for the interested reader to write a recursive function that can implement these functions recursively (hint: the return value would need to be an array)!

Another thing we might want to do with an array is to search it for all values meeting certain criteria. JavaScript provides the filter method to enable us to do just that. The filter method takes as its argument a callback function which is applied to each element in the array on which it is called, and returns a new array containing those elements that pass the test implemented by the callback function.

Suppose we have an array that contains the names of many different kinds of vegetables. We don't know that the correct name of the vegetable we are looking for, but we are pretty certain that it contains a certain sequence of letters. It would be useful if we could apply a filter to the array so that just the names of vegetables containing that sequence of letters, in order to narrow down our search. The HTML code below creates a web page that allows the user to input a search term and display a list of vegetables whose names contain that term. Here is the code:

<!doctype html>
<html lang="en">

  <head>
    <meta charset="utf-8">
    <title>JavaScript Demo 27</title>
    <style>
      .center { text-align: center; }
      button { width: 5em; }
      input { width: 10em; }
    </style>
    <script>
      const vegArray = [ "Asparagus", "Aubergine", "Avocado", "Beetroot", "Broccoli", "Brussels sprouts", "Cabbage", "Carrot", "Cauliflower", "Celery", "Courgette", "Cucumber", "Fennel", "Lettuce", "Mushroom", "Onion", "Parsnip", "Peas", "Potato", "Pumpkin", "Radish", "Spinach", "Squash", "Swede", "Sweet potato", "Tomato", "Turnip" ];

      let inString = "";
      let outString = "";

      function findString(element, index, array) {
        return element.toLowerCase().includes(inString);
      }

      function findVeg () {
        document.getElementById("result").innerHTML = "";
        inString = document.getElementById("searchTerm").value;
        if (inString == "") {
          document.getElementById("result").innerHTML = "<p>You must enter a search term . . . </p>";
          return;
        }
        else {
          const vegResults = [].concat(vegArray.filter(findString));
          if (vegResults.length == 0) {
            outString = "<p>The search term you entered produced no results.</p>";
          }
          else {
            outString = "<p>Your search produced the following results:</p><ul>";
            for (i = 0; i < vegResults.length; i++) {
              outString += "<li>" + vegResults[i] + "</li>";
            }
            outString += "</ul>"
          }
          document.getElementById("result").innerHTML = outString;
          return;
        }
      }
    </script>
  </head>

  <body>
    <div class="center">
      <h1>Find a Veggie</h1>
      <p><strong>Enter a search term:</strong></p>
      <p><input type="text" id="searchTerm"></p>
      <p><button onclick="findVeg()">Search</button></p>
      <div id="result"></div>
    </div>
  </body>
</html>

Copy and paste this code into a new file in your HTML editor, save the file as javascript-demo-28.html, and open the file in a web browser. Enter a search term, and click on the "Search" button. Depending on the search term you enter, you should see something like this:


The script enables the user to filter an array of vegetable names

The script enables the user to filter an array of vegetable names


the callback function used by the filter method in this script is findString(), which is passed as a parameter to the filter method by the findVeg() function. The filter method is called on vegArray and the result assigned to vegResults in this line of code:

const vegResults = vegArray.filter(findString);

Note that, like other search methods we have looked at, filter is not recursive. It could, however, be used to search an array of objects (including an array of arrays) based on a specific value. The HTML code below creates a web page that displays a student class list consisting of the name of each student and the grade they achieved. The page displays all students by default, but allows the user to select a specific grade letter, and display only those students that achieved that grade. Here is the code:

<!doctype html>
<html lang="en">

  <head>
    <meta charset="utf-8">
    <title>JavaScript Demo 29</title>
    <style>
      .center { text-align: center; }
      button { width: 10em; }
      select { width: 10em; }
      table { margin: auto; }
      table, th, td { border: 1px solid grey; }
      th, td { padding: 0 1em; }
      tr td:first-child { text-align: left; }
    </style>
    <script>
      const students = [ ["Anders, B", "F"], ["Collins, J", "A"], ["Dean, N", "C"], ["Grisham, J", "C"], ["Harris, B", "D"], ["Jones, J", "A"], ["Knight, P", "F"], ["Lennon, J", "C"], ["Miller, J", "E"], ["Morton, C", "B"], ["Oldfield, M", "B"], ["Richards, K", "C"], ["Thompson, T", "D"], ["White, C", "A"], ["Young, P", "E"] ];

      let grade = "";
      let tableString = "";

      function sortByGrade(element, index, array) {
        if(grade == "") {
          return element;
        }
        else {
          if (element[1] == grade) {
            return element;
          }
        }
      }

      function createList () {
        tableString = "";
        grade = document.getElementById("grade").value;
        const gradeSort = students.filter(sortByGrade);
        document.getElementById("gradeTable").innerHTML = "";
        tableString += "<table><caption>Student Grades</caption><tr><th>Name</th><th>Grade</th></tr>";
        for( i = 0; i < gradeSort.length; i++ ) {
          tableString += ("<tr><td>" + gradeSort[i][0] + "</td><td>" + gradeSort[i][1] + "</td></tr>");
        }
        tableString += "</table>";
        document.getElementById("gradeTable").innerHTML = tableString;
        return;
      }
    </script>
  </head>

  <body onLoad="createList()">
    <div class="center">
      <h1>Class list</h1>
      <p><strong>Search by grade:</strong></p>
      <p>
        <select name="grade" id="grade">
          <option value="">All grades</option>
          <option value="A">A</option>
          <option value="B">B</option>
          <option value="C">C</option>
          <option value="D">D</option>
          <option value="E">E</option>
          <option value="F">F</option>
        </select>
          
        <button onclick="createList()">Update list</button>
      </p>
      <div id="gradeTable"></div>
    </div>
  </body>
</html>

Copy and paste the code into a new file in your HTML editor, save the file as javascript-demo-29.html, and open the file in a web browser. Use the drop-down menu to select various grades and click on the "Update" button to update the class list. Depending on which grade is selected, you should see something like this:


The script enables the user to filter an array of student records by grade

The script enables the user to filter an array of student records by grade


The filter method is called on the students array, and takes as its argument the sortByGrade() callback function. Each element of the students array is itself an array consisting of two elements - a student name and a grade. The sortByGrade() function compares the value of each student's grade with the value selected by the user, and returns an array containing only those student records with a grade matching the user selection. If the user selects "All grades", no comparison is carried out, and all student records will be displayed.

Note that if we were developing a serious application, the student record would probably be defined as an object rather than an array. We have used an array here for convenience, and in order to keep the code as simple as possible.

The next method we will look at is find. This method also takes a callback function as its argument, but returns only one element - the first element in the array on which it is called that satisfies the test implemented by the callback function (or undefined, if no element passes the test). The following code demonstrates how find works:

let inString = "";

function findString(element, index, array) {
  return element.toLowerCase().includes(instring);
}
const vegArray = [ "Asparagus", "Aubergine", "Avocado", "Beetroot", "Broccoli", "Brussels sprouts", "Cabbage", "Carrot", "Cauliflower", "Celery", "Courgette", "Cucumber", "Fennel", "Lettuce", "Mushroom", "Onion", "Parsnip", "Peas", "Potato", "Pumpkin", "Radish", "Spinach", "Squash", "Swede", "Sweet potato", "Tomato", "Turnip" ];
instring = "ur";
console.log(vegArray.find(findString)); // Courgette

Note that, like other methods, find does not search arrays recursively. Indeed, our callback function as it stands would throw an exception if one of the elements in the array was itself an array:

let inString = "";

function findString(element, index, array) {
  return element.toLowerCase().includes(instring);
}
const vegArray = [ "Asparagus", "Aubergine", "Avocado", "Beetroot", "Broccoli", "Brussels sprouts", "Cabbage", "Carrot", ["Cauliflower", "Celery", "Courgette"], "Cucumber", "Fennel", "Lettuce", "Mushroom", "Onion", "Parsnip", "Peas", "Potato", "Pumpkin", "Radish", "Spinach", "Squash", "Swede", "Sweet potato", "Tomato", "Turnip" ];
instring = "ur";
console.log(vegArray.find(findString));
// Uncaught TypeError: element.toLowerCase is not a function

We could of course prevent an error from occurring by converting all of the array elements to strings, like this:

let inString = "";

function findString(element, index, array) {
  return element.toString().toLowerCase().includes(instring);
}
const vegArray = [ "Asparagus", "Aubergine", "Avocado", "Beetroot", "Broccoli", "Brussels sprouts", "Cabbage", "Carrot", ["Cauliflower", "Celery", "Courgette"], "Cucumber", "Fennel", "Lettuce", "Mushroom", "Onion", "Parsnip", "Peas", "Potato", "Pumpkin", "Radish", "Spinach", "Squash", "Swede", "Sweet potato", "Tomato", "Turnip" ];
instring = "ur";
console.log(vegArray.find(findString));
// Array(3) [ "Cauliflower", "Celery", "Courgette" ]

The problem here is that we now have the entire sub-array being returned rather than just the value we are looking for. If we want to find the first instance of an element in a multi-dimensional array regardless of the level of nesting, we would have to write a function that recurses into any sub-arrays, maybe something like this:

const vegArray = [ "Asparagus", "Beetroot", "Cabbage", ["Celery", ["Courgette"]], "Fennel", "Mushroom", "Parsnip", "Radish", "Spinach", "Swede", "Turnip" ];

function deepFind (arr, str) {
  let foundStr;
  for( let i = 0; i < arr.length; i++ ) {
    if (Array.isArray(arr[i])) {
      foundStr = deepFind(arr[i], str);
      if (foundStr !== undefined) {
        return foundStr;
      }
    }
    else {
      if (arr[i].toLowerCase().includes(str.toLowerCase())) {
        return arr[i];
      }
    }
  }
}

console.log( deepFind(vegArray, "ur")); // Courgette

Sometimes we might want to find the array index of the first instance of a value that satisfies some criterion in an array rather than the value itself. We can do this using the findIndex method. This method takes a callback function as its main argument, and returns the array index of the first element in the array on which it is called that satisfies the test implemented by the callback function (or -1 if no element passes the test). The following code demonstrates how findIndex works:

const vegArray = [ "Asparagus", "Beetroot", "Cabbage", ["Celery", "Courgette"], "Fennel", "Mushroom", "Parsnip", "Radish", "Spinach", "Swede", "Turnip" ];
let inStr;

function findStr(element, index, array) {
  if(!Array.isArray(element)) {
    return element.toLowerCase().includes(inStr.toLowerCase());
  }
}

inStr = "rad";
console.log( vegArray.findIndex(findStr)); // 7
inStr = "cel";
console.log( vegArray.findIndex(findStr)); // -1

Like other search methods, findIndex does not recurse into nested arrays. Once again, we leave it as an exercise for the interested reader to write a recursive function to find the index of a value in a multidimensional array.

Testing arrays

Sometimes, we want to know something about the composition of an array. For example, we might want to ascertain whether every value in the array satisfies a particular condition. Alternatively, we might want to find out whether at least some of the values in the array meet that condition. JavaScript provides two methods - every and some - that allow us to test an array in this way. Both methods receive a callback function as their main argument, and both methods return true or false, depending on whether all of the elements in the array on which they are called (in the case of every) or at least one of the elements (in the case of some) meet the conditions stipulated by the callback function. Here are a couple of examples:

const sensorArray = [49, 46, 45, 41, 51, 63, 48];

function sensorCheck(element, index, array) {
  return (element >= min) && (element <= max);
}

let min = 40, max = 60;
console.log( sensorArray.every(sensorCheck) ); // false
max = 65;
console.log( sensorArray.every(sensorCheck) ); // true
min = 45;
console.log( sensorArray.every(sensorCheck) ); // false

Here, we have an imaginary set of sensor array values, each of which represents a sensor reading (the sensors could be measuring temperature, pressure or whatever). We simply want to know if any of these values is outside some acceptable range. In this case, we start by specifying a value for min of 40 and a value for max of 60. The first time we invoke the every method on sensorArray it returns false, because one of the array values exceeds the value specified by max. When we increase max to 65, it returns true. When we then Increase min to 45, we again get the result false, because there is now a value in the array that is lower than the value specified by min.

Since what we are essentially interested in here is whether or not any of our sensors are returning values that are outside the specified range, we could just as easily use the some method to determine the state of the sensor array, the only difference being that return values of true and false will have the opposite meaning in terms of how an application will interpret the result. For example:

const sensorArrayValues = [49, 46, 45, 41, 51, 63, 48];

function sensorCheck(element, index, array) {
  return (element < min) || (element > max);
}

let min = 40, max = 60;
console.log( sensorArrayValues.some(sensorCheck) ); // true
max = 65;
console.log( sensorArrayValues.some(sensorCheck) ); // false
min = 45;
console.log( sensorArrayValues.some(sensorCheck) ); // true

It may have occurred to you that, whether you use every or some, the same functionality could be implemented just as easily using a simple for loop. For example:

const sensorArray = [49, 46, 45, 41, 51, 63, 48];

function sensorCheck(min, max, arr) {
  for( i = 0; i < arr.length; i++ ) {
    if ((arr[i] < min) || (arr[i] > max)) {
      return false;
    }
  }
  return true;
}

let min = 40, max = 60;
console.log( sensorCheck( min, max, sensorArray ) ); // false
max = 65;
console.log( sensorCheck( min, max, sensorArray ) ); // true
min = 45;
console.log( sensorCheck( min, max, sensorArray ) ); // false

From the above, we would comment that the use of every or some can make your code a little more compact. Whether there is any significant difference in terms of performance is debatable. You should in any case keep in mind that every always returns true for an empty array. Similarly, some always returns false for an empty array. Keep in mind also that the callback function is not invoked for array indexes that are not assigned a value when one of these methods is called. This will be the case, for example, for so-called sparse arrays, where the index numbers are not assigned sequentially.

Processing arrays

Earlier, we said that arrays are ordered collections of data items that can be used to implement complex data structures such as lists, queues and stacks. The precise reasons for creating such data structures can vary, but the one thing they all have in common is that they can be processed as a single entity. The term processing implies that we will be doing something with, or to, some or all of the elements in an array.

Most of the methods we'll look at here do not modify the array on which they are called. The exception is copyWithin, which we'll look at first. The copyWithin method shallow copies part of an array from its original position within the array to a new position within the array. It takes three parameters - target, start and end, which represent zero-based array indices. The target parameter is required, and specifies the start position for the copied values within the array. The start and end parameters are optional. If both are specified, all array elements from start up to (but not including) end are copied to the position specified by target. For example:

const animals = [ "lion", "tiger", "cat", "dog", "goat", "elephant", "cow" ];
animals.copyWithin(4, 0, 3);
console.log(animals);
// Array(7) [ "lion", "tiger", "cat", "dog", "lion", "tiger", "cat" ]

In this example, we have copied the three elements occupying positions 0 - 2 in the animals array to the fifth position in the array, so that they now occupy the last three slots in the array. The values that previously occupied these positions have been overwritten. As already stated, both the start and end parameters are optional. If end is omitted, everything from start to the end of the array is copied. For example:

const animals = [ "lion", "tiger", "cat", "dog", "goat", "elephant", "cow" ];
animals.copyWithin(4, 0);
console.log(animals);
// Array(7) [ "lion", "tiger", "cat", "dog", "lion", "tiger", "cat" ]

As you can see, the result is exactly the same as we had previously. This is because copyWithin does not change the length of an array. Any copied array values that would occupy positions beyond the end of the array are simply discarded. We could of course do something like this:

const animals = [ "lion", "tiger", "cat", "dog", "goat", "elephant", "cow" ];
animals[10] = "";
animals.copyWithin(4, 0);
console.log(animals);
// Array(11) [ "lion", "tiger", "cat", "dog", "lion", "tiger", "cat", "dog", "goat", "elephant", … ]
console.log(animals[10]); // cow

We have essentially increased the length of the array by inserting a value, albeit the empty string, at index 10. We don't generally recommend using this method to increase the length of an array unless you are going to fill the additional spaces with values. The result of doing so otherwise would be a sparse array (basically, an array with gaps in it) which can lead to some unexpected results when processing the array. It also means that the array's length property will no longer accurately reflect the actual number of elements in the array.

Note also that, if either the target parameter or the start parameter is equal to or greater than animals.length, nothing will be copied. The copyWithin method does not change the length of the array. In terms of use cases, we have so far been unable to identify a real-world example of where the copyWithin method might be used. One possible scenario would be a situation in which a specific group of array elements is required to be duplicated at pre-determined intervals throughout an array.

Sometimes, we might want to produce a new flattened array that contains all of the elements in an existing array regardless of the level at which those elements exist within the original array, or perhaps to some pre-determined level of nesting. In order to do this programmatically for a multi-dimensional array, we would need to use recursion. There is no need to do this, however, since we can use the flat method to achieve the desired result. For example:

const arr1 = [1, 2, [3, 4, [5, 6, [7, 8, 9]]]];
const arr2 = arr1.flat();
console.log(arr2); // Array(5) [1, 2, 3, 4, [5, 6, [7, 8, 9]]]

Note that, in this example, we have omitted the optional depth argument, which specifies the depth to which the array is flattened. When omitted, depth defaults to 1, so the array has only been flattened to the first level. If we wanted to flatten the array to the second level, we could do so as follows:

const arr1 = [1, 2, [3, 4, [5, 6, [7, 8, 9]]]];
const arr2 = arr1.flat(2);
console.log(arr2); // Array(7) [[1, 2, 3, 4, 5, 6, [7, 8, 9]]

We can also ensue that the array is completely flattened if desired, regardless of the level to which the array elements are nested, by passing the value Infinity as the depth argument:

const arr1 = [1, 2, [3, 4, [5, 6, [7, 8, 9]]]];
const arr2 = arr1.flat(Infinity);
console.log(arr2); // Array(9) [ 1, 2, 3, 4, 5, 6, 7, 8, 9 ]

Again, it is difficult to find real-world use cases for the flat method, but you might use it (for example) to flatten a multi-dimensional array in order to make it easier to search for a particular value. The flatMap method does something similar to flat, except that it applies the map method to the target array before flattening it. For that reason, we'll postpone a discussion of flatMap until we've looked at how the map method works.

The map method takes a callback function as its main parameter, which is then applied to every element in the calling array. It returns a new array containing the values generated by the application of the callback function to the original array values. For example:

const oldPrices = [3.00, 5.00, 2.50];

function priceIncrease(currentValue, index, array) {
  return currentValue * 1.25;
}

const newPrices = oldPrices.map(priceIncrease);

console.log(newPrices); // Array(3) [ 3.75, 6.25, 3.125 ]

The flatMap method is equivalent to the application of the map method to an array, followed by the application of the flat method, with a depth argument of 1, to the resulting array. For example:

const oldPrices = [3.00, 5.00, 2.50];

function priceIncrease(currentValue, index, array) {
  return [currentValue, currentValue * 1.25];
}

const priceChanges = oldPrices.flatMap(priceIncrease);

console.log(priceChanges);
// Array(6) [ 3, 3.75, 5, 6.25, 2.5, 3.125 ]

The forEach method is similar to the map method in that it takes a callback function as its primary argument and applies it to every element in the calling array. Unlike map, however, the value returned by forEach is undefined and not a new array - although we can of course use it to generate a new array. Here is an example:

const animals = ["lion", "tiger", "elephant", "monkey"];
const animalsUpperCase = [];

function capitalise(currentValue, index, array) {
  animalsUpperCase.push(currentValue.toUpperCase());
}

animals.forEach( capitalise );

console.log( animals );
// Array(4) [ "lion", "tiger", "elephant", "monkey" ]
console.log( animalsUpperCase );
// Array(4) [ "LION", "TIGER", "ELEPHANT", "MONKEY" ]
console.log( animals.forEach( capitalise ) );
// undefined

Sometimes, we might want to create a string variable that contains all of the elements in an array. JavaScript provides two methods for achieving this. The toString method simply returns a string consisting of all of the elements in the array on which it is called, separated by a comma:

const animals = ["lion", "tiger", "elephant", "monkey"];
console.log(animals.toString());
// lion,tiger,elephant,monkey

Note that you do not always need to explicitly invoke the toString method. For example, if an array is concatenated with a string value, the toString method is automatically invoked:

let sentence = "Examples of animals: ";
const animals = ["lion", "tiger", "elephant", "monkey"];
console.log( sentence + animals );
// Examples of animals: lion,tiger,elephant,monkey

The second method we will look at here is the join method, which takes an optional separator argument that allows us to specify what symbol (or sequence of symbols) should be used to separate the array elements in the resulting string. When used without the separator argument, join behaves in the same way as toString:

const animals = ["lion", "tiger", "elephant", "monkey"];
console.log(animals.join());
// lion,tiger,elephant,monkey

The join method gives us the flexibility to define our own separator string. For example:

const animals = ["lion", "tiger", "elephant", "monkey"];
console.log(animals.join(" *** "));
// lion *** tiger *** elephant *** monkey

Note that if the calling array only has one value, the string returned by join contains only that value, and the separator is omitted. Similarly, if the calling array is empty, join simply returns the empty string.

JavaScript provides two so-called reduction methods - reduce and reduceRight - that allow us to reduce an array to a single result. The reduce method takes a callback function as its main argument. The callback function usually takes two arguments - the accumulator argument, to which the result of each iteration of the callback function is added, and the currentValue argument, which is the value of the array element to which the current iteration of the callback function is applied.

By default, the initial value of accumulator is the first element in the array, and the callback function processes the array starting with the second element. However, reduce also takes an optional initialValue argument that can be used to specify the initial value of accumulator. If initialValue is specified, the callback function processes the array starting with the first element. For example:

const numbers = [2, 4, 6, 8, 10];

function sumSquares(sum, value) {
  return sum + value * value;
}

console.log(numbers.reduce(sumSquares)); // 218
console.log(numbers.reduce(sumSquares, 0)); // 220

The reduceRight method essentially does the same thing as the reduce method, except that it processes the elements from right to left instead of from left to right. In this case, the initial value of accumulator is the last element in the array and the callback function processes the array (from right to left) starting with the second to last element. If initialValue is specified, the callback function processes the array starting with the last element. For example:

const numbers = [2, 4, 6, 8, 10];

function sumSquares(sum, value) {
  return sum + value * value;
}

console.log(numbers.reduceRight(sumSquares)); // 130
console.log(numbers.reduceRight (sumSquares, 0)); // 220

In the above examples, reduce and reduceRight produce identical results if initialValue is specified, but very different results when it is omitted. They will allways return the same result if initialValue is specified and the operation implemented by the callback function is commutative, e.g. addition or multiplication, since the order in which the addends or multiplicands appear is unimportant.

The last method we want to look at in terms of processing arrays is slice. We have already seen an example of how slice can be used to clone an array when called on that array without its start and end parameters (or with a start parameter of 0). Its intended purpose, however, is to return a shallow copy of part of an array. For example:

const averageRain = [51, 38, 36, 43, 48, 43, 41, 46, 48, 71, 61, 51];
const summerRain = averageRain.slice(5, 8);
const octToDecRain = averageRain.slice(9);

console.log( summerRain ); // Array(3) [ 43, 41, 46 ]
console.log( octToDecRain ); // Array(3) [ 71, 61, 51 ]

In this example, the averageRain array holds values that represent the average monthly rainfall (in millimetres) for London. In order to obtain the values for the summer only (June to August), we call the slice method on with a start argument of 5 and an end argument of 8. Note that the elements in the new array include the elements of the original array from array index start up to but not including array index end. Note also that if the end argument is omitted, the new array will include all of the elements of the original array from array index start up to the end of the array.

We can also specify a negative value for start if we want to return only the last n values in the array, in which case start will have a value of -n. For example:

const averageRain = [51, 38, 36, 43, 48, 43, 41, 46, 48, 71, 61, 51];
const octToDecRain = averageRain.slice(-3);

console.log( octToDecRain ); // Array(3) [ 71, 61, 51 ]

Array method reference

The table below lists some of the methods available to the JavaScript Array object, gives a brief description of each, and provides examples of their use. Note that some array methods return a new array, while others transform the original array in some way.



JavaScript Array Methods
MethodDescription
concat()

Syntax:

const new_array = old_array.concat([value1[, value2[, ...[, valueN]]]])

Returns a new array that is the result of concatenating the old array with the value and/or array passed to concat() as arguments. For example:

const arr1 = [1, 2, 3];
const arr2 = ["a", "b", "c"];
console.log(arr1.concat(4, 5, 6, arr2));
// [1, 2, 3, 4, 5, 6, "a", "b", "c"]

Using concat() without any arguments returns a shallow copy* of the original array.

copyWithin()

Syntax:

arr.copyWithin(target[, start[, end]])

Returns the modified array produced as a result of shallow copying* part of an array to the location in the array specified by target, overwriting the existing values. The range to be copied is specified by the (optional) start and end parameters. For example:

const myArray = ["a", "b", "c", 4, 5, 6, 7, 8, 9, 10];
console.log(myArray.copyWithin(7, 0, 3));
// ["a", "b", "c", 4, 5, 6, 7, "a", "b", "c"]

The target, start and end parameters are zero-based indexes. Every element from start up to (but not including) end are copied to the position specified by target.

If either target or start is greater than or equal to arr.length, nothing will be copied. If any of the parameters (target, start or end) are negative, they will be counted from the end.

If end is omitted, copyWithin() will copy from start to the last element in the array. If start is omitted, copyWithin() will copy from index 0.

The copyWithin() method can be likened to a "copy and paste" operation that copies part of an array and pastes it to a different position within the array. If the "copy" and "paste" regions overlap, the "pasted" values will overwrite the "copied" values. For example:

const myArray = ["a", "b", "c", 4, 5, 6, 7, 8, 9, 10];
console.log(myArray.copyWithin(2, 0, 3));
// ["a", "b", "a", "b", "c", 6, 7, 8, 9, 10]

entries()

Syntax:

array.entries()

Returns a new Array Iterator object that contains the key/value pairs for each index in the array. For example:

const myArray = ["a", "b", "c"];
const iterator = myArray.entries();
console.log(iterator.next().value); // [0, "a"]
console.log(iterator.next().value); // [1, "b"]
console.log(iterator.next().value); // [2, "c"]

every()

Syntax:

arr.every(callback(element[, index[, array]])[, thisArg])

Returns true or false, depending on whether all of the elements in the array pass the test implemented by the function provided. For example:

function isOdd(element, index, array) {
  return element %2;
}
const myArray = [1, 3, 5, 7, 9];
console.log(myArray.every(isOdd)); // true

The callback parameter is the function used to test each element. It takes three arguments:

  • element - the current element being tested
  • index - the index of the current element being tested (optional)
  • array - the array every() was called on (optional)

The optional thisArg parameter is a value to use as this when executing callback. If thisArg is not specified, a value of undefined will be used as this.

The callback function is executed for each element in the array unless, or until, it finds an element that produces a falsy result, in which case every() immediately returns false. If every element produces a truthy result (or if the array is empty), every() returns true.

Note that the callback function is only invoked for array indexes that are currently assigned a value, and will not be invoked for elements that are appended to the array after the call to every() begins.

If the value of an array element changes after the call to every() begins, the value passed to the callback function will be whatever value it has at the time it is processed by the callback function.

fill()

Syntax:

arr.fill(value[, start[, end]])

Fills the elements of an array with a static value, overwriting the existing values and returning the modified array. The range of elements to be filled is specified by the (optional) start and end parameters. For example:

const myArray = [1, 2, 3, 4, 5, 6, 7];
console.log(myArray); // [1, 2, 3, 4, 5, 6, 7]
console.log(myArray.fill("x", 2, 5)); // [1, 2, "x", "x", "x", 6, 7]

The start and end parameters are zero-based indexes. Every element from start up to (but not including) end is filled with the value specified by value.

If start is negative, it is treated as array.length + start. Similarly, if end is negative, it is treated as array.length + end.

If end is omitted, fill() will fill elements from start to the last element in the array. If start is omitted, fill() will fill elements starting from index 0.

filter()

Syntax:

let newArray = arr.filter(callback(element[, index, [array]])[, thisArg])

Returns a new array containing all of the elements from the calling array that pass the test implemented by the function provided. For example:

function isOdd(element, index, array) {
  return element %2;
}
const myArray = [1, 2, 3, 4, 5, 6];
console.log(myArray.filter(isOdd)); // [1, 3, 5]

The callback parameter is the function used to test each element. It takes three arguments:

  • element - the current element being tested
  • index - the index of the current element being tested (optional)
  • array - the array filter() was called on (optional)

The optional thisArg parameter is a value to use as this when executing the callback function. If thisArg is not specified, a value of undefined will be used as this.

The callback function is executed for each element in the calling array and constructs a new array from those elements that produce a truthy result.

Note that the callback function is only invoked for array indexes that are currently assigned a value, and will not be invoked for elements that are appended to the array after the call to filter() begins.

If the value of an array element changes after the call to filter() begins, the value passed to the callback function will be whatever value it has at the time it is processed by the callback function.

find()

Syntax:

arr.find(callback(element[, index[, array]])[, thisArg])

Returns the value of the first element in the calling array that passes the test implemented by the function provided, or undefined if none of the elements in the calling array pass the test. For example:

const range = [33, 35, 37, 39];
function isPrime(element, index, array) {
  for(var i = 2; i < element; i++) {
    if(element % i === 0) {
      return false;
    }
  }
  return element > 1;
}
console.log(range.find(isPrime)); // 37

The callback parameter is the function used to test each element. It takes three arguments:

  • element - the current element being tested
  • index - the index of the current element being tested (optional)
  • array - the array find() was called on (optional)

The optional thisArg parameter is a value to use as this when executing the callback function. If thisArg is not specified, a value of undefined will be used as this.

The callback function is executed for each element in the array until it finds an element that produces a truthy result, in which case find() immediately returns the value of that element. If no element produces a truthy result, find() returns undefined.

The callback function is invoked for all array indexes, including those that are currently not assigned a value, but will not be invoked for elements that are appended to the array after the call to find() begins.

If the value of an array element changes after the call to find() begins, the value passed to the callback function will be whatever value it has at the time it is processed by the callback function.

findIndex()

Syntax:

arr.findIndex(callback(element[, index[, array]])[, thisArg])

Returns the index of the first element in the calling array that passes the test implemented by the function provided, or -1 if none of the elements in the calling array pass the test. For example:

const range = [33, 35, 37, 39];
function isPrime(element, index, array) {
for(let i = 2; i < element; i++)
  if(element % i === 0) {
    return false;
  }
  return element > 1;
}
console.log(range.findIndex(isPrime)); // 2

The callback parameter is the function used to test each element. It takes three arguments:

  • element - the current element being tested
  • index - the index of the current element being tested (optional)
  • array - the array findIndex() was called on (optional)

The optional thisArg parameter is a value to use as this when executing the callback function. If thisArg is not specified, a value of undefined will be used as this.

The callback function is executed for each element in the array until it finds an element that produces a truthy result, in which case findIndex() immediately returns the index of that element. If no element produces a truthy result, findIndex() returns -1.

The callback function is invoked for all array indexes, including those that are currently not assigned a value, but will not be invoked for elements that are appended to the array after the call to findIndex() begins.

If the value of an array element changes after the call to findIndex() begins, the value passed to the callback function will be whatever value it has at the time it is processed by the callback function.

flat()

Syntax:

var newArray = arr.flat([depth]);

Returns a new array with all sub-array elements concatenated into it recursively up to the specified depth. For example:

const array = ["a", "b", ["c", "d"]];
console.log(array.flat()); // ["a", "b", "c", "d"]

const array = ["a", "b", ["c", "d", ["e", "f"]]];
console.log(array.flat()); // ["a", "b", "c", "d", ["e", "f"]]

const array = ["a", "b", ["c", "d", ["e", "f"]]];
console.log(array.flat(2)); // ["a", "b", "c", "d", "e", "f"]

const array = ["a", "b", ["c", "d", ["e", "f", ["g", "h", ["i", "j"]]]]];
console.log(array.flat(Infinity)); // ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j"]

The optional depth argument specifies the depth to which the calling array should be flattened. If no value is specified for depth, a default value of 1 is used.

In the second example above, the calling array has two nested sub-arrays, the second of which is nested within the first. Because no depth argument is specified, only the first level of nesting is affected by the flat() method.

The same array is used for the third example, but because a depth argument of 2 is specified, both the first and second levels of nesting are affected by the flat() method.

The use of Infinity as the depth argument in the final example ensures that all sub-arrays will be flattened, regardless of the depth to which they are nested.

flatMap()

Syntax:

var newArray = arr.flatMap(callback(currentValue[, index[, array]])[, thisArg])

Returns a new array that is the result of applying the map() function to the calling array and then applying the flat() function (with a depth argument of 1) to the resulting array. For example:

function times2(currentValue, index, array) {
  return [currentValue, currentValue * 2];
}
let arr = [2, 3, 4]
console.log(arr.map(times2).flat()); // [2, 4, 3, 6, 4, 8]


function times2(currentValue, index, array) {
  return [currentValue, currentValue * 2];
}
let arr = [2, 3, 4]
console.log(arr.flatMap(times2)); // [2, 4, 3, 6, 4, 8]

The callback parameter is the function to be applied to each element in the calling array. It takes three arguments:

  • currentValue - the value of the current element being processed
  • index - the index of the current element being processed (optional)
  • array - the array map() was called on (optional)

The optional thisArg parameter is a value to use as this when executing the callback function. If thisArg is not specified, a value of undefined will be used as this.

The callback function is applied to each element in the calling array and constructs a new array from the resulting values. This array is then flattened to a depth of one nested level, and returned as a new array by flatMap().

forEach()

Syntax:

arr.forEach(callback(element [, index [, array]])[, thisArg])

Applies the function provided to every element of the calling array. The return value of this method is undefined. For example:

let arraySum = 0;
function sum(currentValue, index, array) {
  arraySum += currentValue;
}
const numbers = [1, 2, 3, 4, 5];
numbers.forEach(sum);
console.log(arraySum); // 15

The callback parameter is the function to be applied to each element in the calling array. It takes three arguments:

  • currentValue - the value of the current element being processed
  • index - the index of the current element being processed (optional)
  • array - the array forEach() was called on (optional)

The optional thisArg parameter is a value to use as this when executing the callback function. If thisArg is not specified, a value of undefined will be used as this.

Note that the callback function is only invoked for array indexes that are currently assigned a value, and will not be invoked for elements that are appended to the array after the call to forEach() begins.

If the value of an array element changes after the call to forEach() begins, the value passed to the callback function will be whatever value it has at the time it is processed by the callback function.

from()

Syntax:

Array.from(arrayLike[, mapFn[, thisArg]])

Returns a new shallow-copied* array constructed from an array-like object (i.e. an object that has a length property and indexed elements) or an iterable object (e.g. map or set). For example:

newArray = Array.from('abc');
console.log(newArray); // ["a", "b", "c"]

The optional mapFn parameter specifies a mapping function that should be applied to each element of the array-like object passed to the from() method as its first parameter. For example:

newArray = Array.from([2,3,4], x => x+2); console.log(newArray); // [4, 5, 6]

The optional thisArg parameter is a value to use as this when executing mapFn.

If the first parameter passed to from() is either an empty array or is not an array-like object, from() returns an empty array. For example

newArray = Array.from([]);
console.log(newArray); // []

let x = 2;
newArray = Array.from(x);
console.log(newArray); // []

If the first parameter passed to from() is an object that has a non-zero length property but is otherwise undefined, the from() method thinks it is an iterable object, creates an arry of that length, and sets each array element to undefined. For example:

let obj = {length : 2};
newArray = Array.from(obj);
console.log(newArray); // [undefined, undefined]

includes()

Syntax:

arr.includes(valueToFind[, fromIndex])

Tests whether valueToFind is present in the array. If the element is found, includes() returns true, otherwise it returns false. For example:

const myArray = [2,3,5,7];
console.log(myArray.includes(5)); // true
console.log(myArray.includes(5,3)); // false
console.log(myArray.includes(7,3)); // true

const animals = ["cow", "pig", "sheep"];
console.log(animals.includes("cow")); // true
console.log(animals.includes("rabbit")); // false
console.log(animals.includes("Cow")); // false

If the optional fromIndex parameter is positive, it indicates the position in the array at which to begin searching for valueToFind. If fromIndex is negative, the search proceeds in the reverse direction, starting from the position indicated by arr.length + fromIndex (i.e. using the absolute value of fromIndex as the number of elements from the end of the array at which to start the search). If omitted, fromIndex defaults to 0.

Note that when comparing strings and characters, includes() is case sensitive.

indexOf()

Syntax:

arr.indexOf(searchElement[, fromIndex])

Returns the index of the first instance of searchElement found in the array, or -1 if it is not found. For example:

const insects = ["ant", "bee", "wasp", "fly", "bee"];
console.log(insects.indexOf("wasp")); // 2
console.log(insects.indexOf("bee", 2)); // 4
console.log(insects.indexOf("spider")); // -1

If the optional fromIndex parameter is positive, it indicates the position in the array at which to begin searching for valueToFind. If fromIndex is equal to or greater than arr.length, the array is not searched and -1 is returned. If fromIndex is negative, the search proceeds in the reverse direction, starting from the position indicated by arr.length + fromIndex (i.e. using the absolute value of fromIndex as the number of elements from the end of the array at which to start the search). If omitted, fromIndex defaults to 0.

Note that when comparing strings and characters, indexOf() is case sensitive.

isArray()

Syntax:

Array.isArray(value)

Returns true if value is an Array, otherwise returns false. For example:

console.log(Array.isArray([1,2,3,4]));
console.log(Array.isArray("Some text"));
console.log(Array.isArray(10));

join()

Syntax:

arr.join([separator])

Returns a string created by concatenating all of the elements in an array (or an array-like object), separated by commas or a specified separator string. If the array has only one item, then that item will be returned without using the separator. For example:

const compass = ["North", "South", "East", "West"];
console.log(compass.join()); // North,South,East,West
console.log(compass.join('-')); // North-South-East-West

const digits = [1,2,3,4];
console.log(digits.join()); // 1,2,3,4
console.log(digits.join('')); // 1234
console.log(digits.join('-')); // 1-2-3-4

The optional separator parameter specifies a string to separate each pair of adjacent array elements in the returned string. If omitted, the array elements are separated by a comma. If the separator is an empty string, the array elements are simply concatenated in the returned string.

If arr.length is 0, the empty string is returned.

keys()

Syntax:

arr.keys()

Returns a new Array Iterator object that contains the keys for each index in the array. For example:

const months = ["January", "February", "March"];
const iterator = months.keys();

for (const key of iterator) {
  console.log(key, months[key]);
}
// 0 January
// 1 February
// 2 March

const digits = [1,2,3,4,5];
const iterator = digits.keys();
console.log(...iterator); // 0 1 2 3 4

lastIndexOf()

Syntax:

arr.lastIndexOf(searchElement[, fromIndex])

Returns the index of the last instance of searchElement found in the array, or -1 if it is not found. For example:

const insects = ["ant", "bee", "wasp", "fly", "bee"];
console.log(insects.lastIndexOf("wasp")); // 2
console.log(insects.lastIndexOf("bee")); // 4
console.log(insects.lastIndexOf("spider")); // -1

If the optional fromIndex parameter is positive, it indicates the position in the array at which to begin searching backwards for valueToFind. If fromIndex is equal to or greater than arr.length, the entire array is searched. If fromIndex is negative, the search proceeds backwards from the position indicated by arr.length + fromIndex. If the calculated value is less than 0, the array will not be searched and -1 will be returned. If fromIndex is omitted, it will default to arr.length - 1.

Note that when comparing strings and characters, lastIndexOf() is case sensitive.

map()

Syntax:

let new_array = arr.map(callback(currentValue[, index[, array]])[, thisArg])

Returns a new array containing the results of applying the function provided to all of the elements in the calling array. For example:

function square(currentValue, index, array) {
  return currentValue * currentValue;
}
const numbers = [1, 2, 3, 4, 5];
console.log(numbers.map(square)); // [1, 4, 9, 16, 25]

The callback parameter is the function to be applied to each element in the calling array. It takes three arguments:

  • currentValue - the value of the current element being processed
  • index - the index of the current element being processed (optional)
  • array - the array map() was called on (optional)

The optional thisArg parameter is a value to use as  this when executing the callback function. If thisArg is not specified, a value of undefined will be used as  this.

The callback function is applied to each element in the calling array and constructs a new array from the resulting values.

Note that the callback function is only invoked for array indexes that are currently assigned a value (including a value of undefined), and will not be invoked for elements that are appended to the array after the call to map() begins.

If the value of an array element changes after the call to map() begins, the value passed to the callback function will be whatever value it has at the time it is processed by the callback function.

of()

Syntax:

Array.of(element0[, element1[, ...[, elementN]]])

Creates a new Array instance from a variable number of arguments, regardless of number or type of the arguments. For example:

const insects = Array.of("ant", "bee", "fly");
const digits = Array.of(1,2,3,4,5);
const misc = Array.of(1,"Frog",2.7183);
console.log(insects); // Array(4) ["ant", "bee", "fly"]
console.log(digits); // Array(5) [1, 2, 3, 4, 5]
console.log(misc); // Array(3) [1, "Frog", 2.7183]

pop()

Syntax:

arr.pop()

Removes the last element from an array (or an array-like object) and returns that element. The pop() method changes the length of the array. For example:

const primes = [2,3,5,7,11];
let popped = primes.pop();
console.log(primes); // Array(4) [2, 3, 5, 7]
console.log(popped); // 11

Note that if the pop() method is applied to an object that doesn't have a length property, or to an empty array, it returns undefined. Note also that the pop() method cannot be used with a string or argument object, because these objects are immutable.

push()

Syntax:

arr.push([element1[, ...[, elementN]]])

Adds one or more elements to the end of an array (or an array-like object) and returns the new length of the array.

const primes = [2,3,5];
console.log(primes); // Array(3) [2, 3, 5]
primes.push(7,11);
console.log(primes); // Array(5) [2, 3, 5, 7, 11]

Note that the push() method cannot be used with a string or argument object, because these objects are immutable.

reduce()

Syntax:

arr.reduce(callback( accumulator, currentValue, [, index[, array]] )[, initialValue])

Executes the callback function on each element of the array, and returns a single output value. For example:

const myArray = [1, 2, 3, 4];
const reducer = (result, val) => result + val;
console.log(myArray.reduce(reducer)); // 10
console.log(myArray.reduce(reducer, 5)); // 15

The callback parameter is the function to be applied to each element in the calling array. It takes four arguments:

  • accumulator - accumulates the values returned by the callback function - it is the accumulated value previously returned in the last invocation of the callback function, or initialValue if it was supplied
  • currentValue - the current element being processed
  • index - (optional) the index of the current element being processed (starts from 0 if initialValue is provided, otherwise starts from 1)
  • array - the array reduce() was called on (optional)

The value returned by the callback function is added to accumulator, the value of which is retained after each iteration of the callback function. The final value of accumulator is the value returned by the reduce() method.

If initialValue is omitted, the callback function takes the first value in the array as the initial value of accumulator and processes the array elements starting at the second element in the array, otherwise it processes the array elements starting with the first element. Note that calling reduce() on an empty array without specifying initialValue will result an error.

reduceRight()

Syntax:

arr.reduceRight(callback(accumulator, currentValue[, index[, array]])[, initialValue])

Executes the callback function on each element of the array from right to left, and returns a single output value. For example:

const myArray = ["end.", "the ", "is ", "This "];
const reducer = (result, val) => result + val;
console.log(myArray.reduceRight(reducer));
// This is the end.
console.log(myArray.reduceRight(reducer, "Omega. "));
// Omega. This is the end.

This method is same as the reduce() method, except that the callback function processes the array elements from right to left.

reverse()

Syntax:

arr.reverse()

Reverses the order of an array and returns a reference to the array - the first array element becomes the last, and the last array element becomes the first. For example:

const myArray = [1,2,3,4,5];
console.log(myArray); // Array(5) [1, 2, 3, 4, 5]
myArray.reverse();
console.log(myArray); // Array(5) [5, 4, 3, 2, 1]

shift()

Syntax:

arr.shift()

Removes the first element from an array (or an array-like object) and returns that element. The shift() method changes the length of the array. For example:

const primes = [2,3,5,7,11];
console.log(primes); // Array(5) [2, 3, 5, 7, 11]
let shifted = primes.shift();
console.log(primes); // Array(4) [3, 5, 7, 11]
console.log(shifted); // 2

Note that if the shift() method is applied to an object that doesn't have a length property, or to an empty array, it returns undefined. Note also that the shift() method cannot be used with a string or argument object, because these objects are immutable.

slice()

Syntax:

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

Returns a shallow copy* of part of an array, from arr[start] to arr[end-1]. The original array is not modified. For example:

const primes = [2,3,5,7,11,13];
let newPrimes = primes.slice(2,5);
console.log(newPrimes); // Array(3) [5, 7, 11]

If end is omitted, or is equal to or greater than arr.length, slice() extracts all array elements from arr[start] to the end of the array. For example:

const primes = [2,3,5,7,11,13];
let newPrimes = primes.slice(2);
console.log(newPrimes); // Array(4) [5, 7, 11, 13]

If start is undefined, slice() starts from the first array element. For example:

const primes = [2,3,5,7,11,13];
let start;
let newPrimes = primes.slice(start, 3);
console.log(newPrimes); // Array(3) [2, 3, 5]

If a negative value is used for start, it indicates an offset from the end of the array. For example:

const primes = [2,3,5,7,11,13];
let newPrimes = primes.slice(-3);
console.log(newPrimes); // Array(3) [7, 11, 13]

Similarly, if a negative value is used for end, it indicates an offset from the end of the array. For example:

const primes = [2,3,5,7,11,13];
let newPrimes = primes.slice(2, -2);
console.log(newPrimes); // Array [5, 7]

If start is greater than or equal to arr.length, or if start is greater than or equal to end, an empty array is returned. For example:

const primes = [2,3,5,7,11,13];
let start = primes.length;
let newPrimes = primes.slice(start);
console.log(newPrimes); // Array []


const primes = [2,3,5,7,11,13];
let newPrimes = primes.slice(3, 3);
console.log(newPrimes); // Array []

If used with no parameters, slice() simply returns a copy of the original array.

Note that if any of the array elements being copied are object references, they will point to the same objects in both the original array and the new array. If one of the objects changes, the changes are visible to both arrays.

some()

Syntax:

arr.some(callback(element[, index[, array]])[, thisArg])

Returns true or false, depending on whether or not at least one element in the array passes the test implemented by the function provided. For example:

const primes = [2,3,5,7,11,13];
const even = (element) => element % 2 === 0;
console.log(primes.some(even)); // true

The callback parameter is the function used to test each element. It takes three arguments:

  • element - the current element being tested
  • index - the index of the current element being tested (optional)
  • array - the array some() was called on (optional)

The optional thisArg parameter is a value to use as this when executing the callback function. If thisArg is not specified, a value of undefined will be used as this.

The callback function is executed for each element in the array unless, or until, it finds an element that produces a truthy result, in which case some() immediately returns true. If every element produces a falsy result (or if the array is empty), some() returns false.

Note that the callback function is only invoked for array indexes that are currently assigned a value, and will not be invoked for elements that are appended to the array after the call to some() begins.

If the value of an array element changes after the call to some() begins, the value passed to the callback function will be whatever value it has at the time it is processed by the callback function.

sort()

Syntax:

arr.sort([compareFunction])

Sorts the elements of an array and returns the sorted array. The default sort order is ascending, and the default sorting method converts the array elements into strings and sorts them alphabetically by comparing UTF-16 code unit values. For example:

const insects = ["Wasp","Bee","Ant"];
insects.sort();
console.log(insects); // Array(4) ["Ant", "Bee", "Wasp"]


const numbers = [2,12,34,150,230];
numbers.sort();
console.log(numbers); // Array(5) [12, 150, 2, 230, 34]

The optional compareFunction parameter specifies a function that defines the sort order. The compare function compares two adjacent array elements, a and b, according to some sort criterion. If a is less than b according to the sort criterion, the function returns -1. If a is greater than b according to the sort criterion, the function returns 1. If a is equal to b, the function returns 0. If the value returned by the compare function is -1 or 0, a and b are left where they are, otherwise they are swapped.

To compare numbers instead of strings, the compare function can simply subtract b from a. If the result is greater than 0, a and b are swapped; otherwise they are left where they are. For example:

const numbers = [21,7,98,26,5,48];
numbers.sort(function(a,b) {
  return a - b;
});
console.log(numbers); // Array(6) [5, 7, 21, 26, 48, 98]

splice()

Syntax:

let arrDeletedItems = array.splice(start[, deleteCount[, item1[, item2[, ...]]]])

Changes the contents of an array by removing or replacing existing elements and/or adding new elements, and returns an array containing the deleted items (or an empty array, if no items are deleted). For example:

const months = ["Jan", "Mar", "Apr", "Jun"];
let arrDeleted = months.splice(1, 0, "Feb");
console.log(months);
// Array(5) ["Jan", "Feb", "Mar", "Apr", "Jun"]
console.log(arrDeleted); // Array []
arrDeleted = months.splice(4, 1, "May");
console.log(months);
// Array(5) ["Jan", "Feb", "Mar", "Apr", "May"]
console.log(arrDeleted); // Array ["Jun"]

The start parameter specifies the array index at which to start changing the array. If start is set to a value that is greater than the length of the array, it will be set to arr.length; no elements will be deleted, but splice() will add all of the elements provided in the parameter list. If start is negative, the changes will start from index arr.length + start. If arr.length + start is less than 0, they will start from index 0.

The optional deleteCount parameter is an integer indicating the number of elements to remove from the array, starting from the array index specified by start. If omitted, or if its value is equal to or greater than arr.length – start, all of the elements from start to the end of the array will be removed. If deleteCount is 0 or a negative number, no elements are removed.

Note that if the specified number of elements to insert differs from the number of elements being removed, the value of arr.length will change.

toString()

Syntax:

arr.toString()

Returns a string containing the array elements, separated by a comma.

const myArray = [1,"Jan",2,"Feb",3, "Mar"];
console.log(myArray.toString()); // 1,Jan,2,Feb,3,Mar

If an array is to be represented as a text value, or when an array is referenced in a string concatenation operation, JavaScript calls toString() automatically.

unshift()

Syntax:

arr.unshift(element1[, ...[, elementN]])

Adds one or more elements to the beginning of an array (or an array-like object) and returns the new length of the array. For example:

const myArray = [3, 4, 5];
console.log(myArray.unshift(1, 2)); // 5
console.log(myArray); // Array(5) [1, 2, 3, 4, 5]

values()

Syntax:

arr.values()

Returns a new Array Iterator object that contains the values for each index in the array. For example:

const months = ["Jan", "Feb", "Mar"];
const iterator = months.values();
for (const value of iterator) {
  console.log(value);
}
// Jan
// Feb
// Mar

Note that no values are stored in the Array Iterator object. It stores the address of the array used to create it, and depends on the values stored in that array.



* A shallow copy is a copy of an object that contains all of the values in the original object. However, if any of these values are references to other objects, only the reference addresses are copied. A deep copy also contains all of the values in the original object, but if any of these values are references to other objects, both the referring object and the objects to which it refers are copied.