Arrays
Arrays are the simplest data structure; they are a collection of values, where order matters. Examples of an array include: list of comments on a post, a collection of levels in a game, or a playlist of songs. Every value can be collected and placed in an order. The resulting ordered collection is called an array. Arrays can also collect and order other arrays.
To create an array in JavaScript, we use square brackets []
. Here is an
empty array:
let special_numbers = [];
An array of strings:
let colors = ["red", "orange", "blue", "green"];
An array of numbers:
let primes = [1, 3, 5, 7, 11];
A mixed array:
let randomStuff = [true, 68, "bird", null];
Indices in an Array
The values in an array are indexed, meaning that each value in the array has an index, or position within the array, starting from 0. So, for example:
let colors = ["red", "orange", "yellow", "blue"];
colors[0]; // returns 'red'
colors[1]; // returns 'orange'
colors[2]; // returns 'yellow'
colors[3]; // returns 'blue'
Array Length
Much like how they can be applied to strings and variables, we can find the
length of an array (how many values it holds) with the .length
method.
let colors = ["red", "orange", "yellow", "blue"];
colors.length; // Returns 4, the array named _colors_ contains 4 values.
If we want to get the last value in an array:
let colors = ["red", "orange", "yellow", "blue"];
colors[colors.length - 1]; // returns 'blue';
This works because colors.length returns a number value. That number value is 4, the number of values in the array. Subtract 1, and you have the number 3. So, the code is telling JavaScript, get the value with index of 3 in the array of colors (the index of 3 is the last item in the array.)
Modifying Arrays
Say that we've set an array. We can change the values inside that array by going back and manually changing them, but that would be horribly inefficient (and you likely do no want to do that for a very large program). Instead of manually changing the values in the array, we can use their indices:
let colors = ["red", "blue", "green"];
colors[0] = "purple";
colors[1] = "violet";
colors[2] = "black";
// The above will change the array _colors_ to the following:
colors = ["purple", "violet", "black"];
We can also use methods to change the values in an array:
// Here is our initial shopping list
shoppingList = ["Bud Light", "Merlot", "Vodka", "Tequila"];
// Guest called, wants Cabernet, not Merlot:
shoppingList[1] = "Cabernet";
// Another guest called, wants Rum, not Tequila:
shoppingList[shoppingList.length - 1] = "Rum";
// Yet another guest called, requesting Tequila to be added
shoppingList[shoppingList.length] = "Tequila";
console.log(shoppingList);
['Bud Light', 'Cabernet', 'Vodka', 'Rum', 'Tequila']
Appending
The push()
method adds one or more elements to the end of an array, and
returns the new length of the array.
let vectors = ["w", "x", "y"];
vectors.push("z");
console.log(vectors);
['w', 'x', 'y', 'z']
Removing
The pop()
method removes a value at the end of an array.
let procedures = ["w", "x", "y", "z"];
procedures.pop("z");
console.log(procedures);
['w', 'x', 'y']
Shifting
The shift()
method removes a value from the start of an array:
let procedures = ["w", "x", "y", "z"];
procedures.shift("w");
console.log(procedures);
['x', 'y', 'z']
Unshifting
The unshift()
method adds a value to the start of an array:
let procedures = ["w", "x", "y", "z"];
procedures.unshift("v");
console.log(procedures);
['v', 'w', 'x', 'y', 'z']
Concatenating
The concat()
method creates a new array from merging two arrays; there is
no change to the original.
let x = ["a", "b", "c"];
let y = ["d", "e", "f"];
let xAndy = x.concat(y);
console.log(xAndy);
['a', 'b', 'c', 'd', 'e', 'f']
When using the concat()
method, order matters. So, for example, suppose
you have the following:
array1.concat(array2).concat(array3);
[array1_values, array2_values, array3_values]
Includes
The includes()
method is a Boolean methodβit returns either true or
false. If the value is found in the array, the method returns true. If the
value is not found in the array, the method returns false.
let subjects = ["math", "physics", "cs", "chemistry"];
subjects.includes("physics"); // true
The includes()
method can also take a number as a second argument. The
number passed in represents the starting index for JavaScript's search.
By passing in a number , we essentially ask JavaScript: "Is the value
contained in the part of the array starting from index ? For example:
let var_Array = ['w', 'x', 'y', 'z'];
var_Array.includes('w', var.Array.length / 2); // false
In the code above, we are actually asking: JavaScript, is this true or
false: The value 'w'
is inside the array, and, more specifically, in the
part of the array starting from i = 2
. This returns false, since 'w'
is
in the first half of the array, starting from i = 0
.
indexOf()
The indexOf()
method works in the same way with arrays as it does with
strings. In other words, the indexOf()
method finds the index of a value
in the array. If the method finds the value, it returns its index (an
integer , where ). If the method does not find the value, it
returns -1. Like the includes()
method, we can pass through a second
argument, an integer, into the method's arguments, to specify where the
method should operate.
let frequencies = ["1Mhz", "3Mhz", "7Mhz", "15Mhz"];
frequencies.indexOf("1Mhz");
// This returns 0, the index of '1Mhz'
frequencies.indexOf("3Mhz", frequencies.length / 2);
// This returns -1, because we told JavaScript to only search for '3Mhz' in the part of the array starting from index = 2, and there is no such value in that part of the array.
frequencies.indexOf("7Mhz", frequencies.length / 2);
// This returns 2. We told JavaScript, "Search for '7Mhz' in the part of the array starting from index = 2. JavaScript found the value, and returned its index, 2."
Reversing
The reverse()
method changes the original array by reversing the order of
its values. Note that the reverse()
method changes the original array;
once applied, the original array is replaced by the new array resulting
from the method.
let arr = [1, 2, 3, 4, 5];
arr.reverse();
/*
This changes the original array into:
arr = [5, 4, 3, 2, 1]
*/
Joining
The join()
method takes all the values in an array, and combines them
into a single string, as originally ordered. Remember, the return from a
join()
method is a string. Thus, if you us the join()
method with an
array of numbers, the result is a string of those numbers.
let letters = ["q", "u", "a", "d", "r", "a", "t", "i", "c"];
letters.join("");
// This returns a single string, joined with an empty string: 'quadratic'
letters.join("-");
// This returns a single string, joined with the string '-': 'q-u-a-d-r-a-t-i-c'
letters.reverse().join("");
// This reverses the array _letters_, and returns a single string, joined with an empty string: 'citardauq'
Sub-arrays
Like the slice()
method applied to strings, the slice()
method applied
to arrays takes a portion of an array, and creates a new array with that
portion, without changing or affecting the original array. The slice()
method usually takes two arguments:
- The starting index in the original array to start the slice; and
- The end index in the original array (but, in the slice, it does not include the value with the end index).
If no numbers are passed into the .slice()
method, then an entire copy of
the array is made. So, for example:
let sets = ["A", "B", "C", "D", "E"];
let slicedSets = sets.slice(1, 3);
/* We've created a new array called _slicedSets_:
slicedSets = ['B', 'C']
*/
By passing a negative number, say into the slice()
method, we
essentially tell JavaScript: "For this array, slice the portion starting
from the last index." For example:
let sets = ["A", "B", "C", "D", "E"];
let subSet = sets.slice(-2);
/*
This code says, make a slice starting 2 from the last index (here, the last index is 5, so the slice starts at 3). This will include the last index.
So, the resulting array:
subset = ['C', 'D', 'E']
*/
If 2 negative numbers are passed as arguments into the slice()
method,
say and , then the slice starts at index from the last index
of the array, and the slice ends at index from the last index of the
array. Illustration:
let sets = ["A", "B", "C", "D", "E"];
let subSet = sets.slice(-3, -1);
/*
Here, we tell JavaScript, start the slice at the index 3 units from the last index (in this case, index = 2), and end the slice 1 unit from the last index (index = 4).
Thus:
subSet = ['C', 'D']
*/
Splicing
The splice()
method can either remove, replace, or add new values in an
array. splice()
is primarily used for changes to the middle of an array,
since changes to the beginning or end of an array are usually handled with
push()
, pop()
, shift()
, and unshift()
. Splice can take at least
three different values:
- the start index (an integer)
- the specific value we want to delete
- the specific value we want to insert
So, for example:
let vectors = ["velocity", "acceleration", "momentum"];
vectors.splice(1, 0, "weight");
/*
In the above code, we changed the original array vectors to the following:
vectors = ['velocity', 'weight', 'acceleration', 'momentum']
*/
The splice()
method changes the original array. I.e., once applied, the
original array is no more---it is now the modified, spliced array.
Sorting
The sort()
method sorts the elements of an array in place, and returns
the sorted array. The sort order can be alphabetic, numeric, ascending, or
descending. By default, sort()
sorts an array's elements as strings in
alphabetic and ascending order. To sort the string elements of an array
alphabetically:
let shapes = ["square", "circle", "triangle", "pentagon", "rhombus"];
shapes.sort();
/*
This returns a sorted array:
['circle', 'pentagon', 'rhombus', 'square', 'triangle']
*/
Reference Types
When a variable is declared and assigned a primitive type value, a value type variable is created. Once a value type variable is created, JavaScript stores it in memory, and more specifically, JavaScript stores the variable's assigned value. This is not the case for variables declared and assigned an array.
Arrays are too large and take up memory unnecessarily. Instead of storing
the array, JavaScript stores the array's reference. An array's
reference is a string of numbers, akin to a memory address. This has a
significant impact on the way const
works with arrays.
Because assigning an array to a variable does not actually store the array
in the variable (it stores the array's reference), we can change the
elements within an array, even if we assign the array to a variable
declared with const
.This is because once an array is created and stored
in a variable, its reference never changes.
As such, because the variable declared and assigned with const
is storing
a reference (which never changes), rather than the actual array itself, the
array can be changed later down the program.
This also means that if you declare a variable with const
and assign an
array to it, you cannot change that reference later (i.e., assigning to the
variable an entirely new array). Because of this behavior, it is almost
always the case that const
should be used for arrays, unless there is a
reason for needing a variable to point to different arrays (in which case,
let
should be used).
Nested Arrays
It is perfectly fine to have arrays containing arrays (but, before nesting an array, consider whether there is an alternative or better data structure).
/*
Here is an array containing three arrays.
*/
const courses = [
["mechanics", "E & M", "thermodynamics"],
["calculus", "differential equations", "real analysis"],
["algorithms", "data structures", "operating systems"],
];
To access the elements of a nested array, we can perform the following:
const arr1 = [
[1, 3, 5, 9],
[3, 2, 9, 10],
[11, 3, 6, 9],
];
// Suppose we want the third element of the second array:
arr1[1][2];
/*
This returns 9.
[1] tells JavaScript, look at the element with index of 1---in this case, the second array.
[2] tells JavaScript, inside that array, look at the element with index of 2---in this case, the number 9.
*/
Other Ways to Implement Arrays
Recall that arrays are an ordered collection data structure. In terms of datatype, arrays are objects. Now we're adding another trait: As objects, arrays behave like iterables β a particular kind of object. But, not every iterable is an array. For example, NodeList, String, Map, and Set are all iterables. Objects of these types are iterables, and we can iterate through them with a for-of loop. But, objects of type NodeList are not arrays. They are array-like objects, in that they have a length property, and use indices for accessing.
To better understand the differences between an array and an array-like object, let's revisit arrays. Recall the method for creating arrays we're familiar with:
const arr = [1];
No surprises here. This statement creates a singleton, an array with only one element. It's also the most common way to create an array. But it turns out the above statement isn't the only way:
const arr = Array(1);
const arr = new Array(1);
const arr = Array.of(1);
const arr = Array.from(1);
Although each of the statements above creates an array, they all do so
differently. To see these differences, we revisit the length
property of
an array. We know that when we create an array in JavaScript the way we
usually do (with square brackets) we create an array whose length can grow
and shrink:
let arr = [1, 2, 3];
console.log(arr);
console.log(arr.length);
[1, 2, 3]
3
When use the Array()
function, we get the same result:
let arr = Array(1, 2, 3);
console.log(arr);
console.log(arr.length);
[1, 2, 3]
3
The same goes for new Array()
:
let arr = new Array(1, 2, 3);
console.log(arr);
console.log(arr.length);
[1, 2, 3]
3
Now notice what happens when we pass a single argument:
let arr1 = [1];
let arr2 = Array(1);
let arr3 = new Array(1);
console.log(arr1);
console.log(arr1.length);
console.log(arr2);
console.log(arr2.length);
console.log(arr3);
console.log(arr3.length);
[1]
1
[empty]
1
[empty]
1
When we use the square bracket syntax for initialization (arr1
), we get
an array as expected. But, using Array()
or new Array()
, we get an
empty array with a length of 1
. What's happening here?
We're seeing this behavior because Array()
is a function that returns a
static array if only one argument is passed to it. Both Array()
and
new Array()
are essentially the same. The only difference is that
Array()
is a function, while new Array()
is a constructor. Either or,
passing only one argument is interpreted as the resulting array's length.
Passing multiple arguments, the values are interpeted as the resulting
array's elements.