Creating arrays in JavaScript

Creating arrays in JavaScript is easy with the array literal notation. It consists of two square brackets that wrap optional array elements separated by a comma. Array elements can be any type, including number, string, Boolean, null, undefined, object, function, regular expression and other arrays. Here are some examples:

// empty array with no elements
var empty = [];                       
// array with 2 string elements
var days = ["Sunday", "Monday"];      
// array with elements of different types
var mixed = [false, 2.70, "Hello"];   
// elements can be arbitrary expressions
var suffix = "tree";
var trees = ["Oak" + suffix, "Elm" + suffix];  
// 2 dimensional array with object literals
var array2 = [[1,{x:1, y:2}], [2, {x:3, y:4}]];    
// the 3rd element is undefined
var colors = ["Red", "Green", undefined];    
// no value in the 1st element, it is undefined
var hobbies = [,"Art"];              

Accessing array elements

JavaScript arrays are a special type of object. To access an array item, the [] operator is used, for example colors[2]. The [] operator converts the expression inside the square brackets to a string. For instance, if it is a numeric value, JavaScript converts it to a string and then uses that string as the property name, similar to the square bracket notation of objects to access their properties. This explains why JavaScript arrays are not nearly as fast as arrays in other languages.

In the next example, 0, 1, and 2 are converted to "0", "1", and "2" respectively:

var days = ["Sunday", "Monday"]; // an array with 2 elements
var firstDay = days[0];          // index 0 is converted to "0"
days[1] = "Ford"; 
days[2] = "Tuesday";             // writes element 3

Since an array is a subclass of object, there is nothing to stop you from adding properties on an array instance:

var cars = ["Toyota"];
cars["tires"] = 4;
alert(cars["tires"]);            // => 4
Run



Iterating over JavaScript arrays

Before reviewing iterating over an array we need to understand how to determine how many elements there are in an array. The closest we can get is JavaScript's length property.

The length of JavaScript arrays

JavaScript automatically keeps track of the length property that exists on each array. Unlike other languages, the length of a JavaScript array does not hold the array's upper bound.

var days = ["Sunday", "Monday"];      
alert(days.length);        // => 2
var cars = [];
cars[1] = "Honda";        
cars[3] = "Fiat";         
alert(cars.length);        // =>  4
Run

In this example, the length property of the cars array is greater than the number of elements. The value length is 4, but the actual number of array elements is just 2. So, how does this work? The rule with length is that it is the last numerical index plus one. An array with gaps in its elements is called a sparse array.

Here is another unusual case: an element with the key six is added to the above script, but is ignored by the length property.

cars["six"] = "Volkswagen";
alert(cars.length);        // => still returns 4
Run

These examples also demonstrate that JavaScript arrays are dynamically sized, meaning that you will never see array out-of-bound errors.

Iterating over array elements

With an irregular array how do we iterate over all its elements? Let's first consider using for loops.

var cars = [];
cars[1] = "Ford"; 
cars[3] = "BMW";
cars["six"] = "Honda";
for (var i = 0; i < cars.length; i++) {
    alert(cars[i]);     // => undefined, Ford, undefined, BMW
}
// To skip missing and undefined elements, add this condition.
for (var i = 0; i < cars.length; i++) {
    if (cars[i] === undefined)      // skip undefined elements
        continue;
    alert(cars[i]);          //  => Ford, BMW
}
Run

Notice that the array element with key six won't appear when iterating using a for-loop.

To see all index values we need to use a for-in loop, like so:

var cars = [];
cars[1] = "Ford"; 
cars[3] = "BMW";
cars["six"] = "Honda";
for (var index in cars) {
    alert(cars[index]);        // Ford, BMW, Honda
}
Run

There are a couple of things to be aware of when using a for-in loop on arrays. First, if you are expecting the elements of your array to appear in numerical order, don't trust the for-in loop. They can appear in any order. Secondly, the for-in loop not only returns all array properties (elements), but it also returns the properties that are inherited through the prototype chain.

With both the length property and the for-in loop being somewhat peculiar, it is best to always use numeric index values starting with 0 going up. In that case arrays will behave similar to most other languages and the length property as well as the for-loop will work as you would expect. Here is an example:

var cars = [];
cars[0] = "Ford"; 
cars[1] = "BMW";
cars[2] = "Honda";
alert(cars.length);     // => 3
for (var i = 0, len = cars.length; i < len; i++) {
    alert(cars[i]);       // => Ford, BMW, Honda
}
Run

Multi-Dimensional Arrays

JavaScript does not natively support arrays of more than one dimension; you have to create them yourselves. Fortunately, they are easy to model with arrays of arrays. In the next example we create a 5 by 5 identity matrix with a value of 1 on diagonal elements and 0 everywhere else.

var twoDim = [];
for (var row = 0; row < 5; row++) {
    var oneDim = [];
    for (var col = 0; col < 5; col++) {
        oneDim[col] = (row === col) ? 1 : 0;  // 0 or 1 (diag)
    }
    twoDim[row] = oneDim;
}
alert(twoDim[4][2]);              // => 0
alert(twoDim[3][3]);              // => 1
Run

The last two statements also demonstrate how you would access elements in a 2-dimensional array: simply use the [] operator twice, the first for the row and second for the column index.

Deleting array elements with delete

To remove an element from an array you can use the delete operator. Deleting an element does not affect the length property and the array becomes sparse. Also, elements with higher indexes to the right of the deleted element do not get shifted down to fill in the gap.

var days = ["Sunday", "Monday", "Tuesday", "Wednesday"];
delete days[2];              // => delete the element at index 2
alert(days[2]);              // => undefined
alert(days.length);          // => still 4
Run

An alternative to delete is the built-in array method splice(). The difference with the delete operator is that splice() does not make the array sparse and shifts the elements to higher or lower positions as necessary making sure that no gap is left. This is discussed in the next section.





Array methods: splice(), push(), pop(), shift(), unshift()

A versatile splice() method

The built-in array method splice() is rather versatile and inserts new, deletes existing, and replaces existing elements with new elements in the array. The beauty of splice() is that it does not leave the array sparse because it will shift the elements to higher or lower positions as necessary; there will be no gap left.

The first argument of splice() specifies the ordinal position at which the operation is to start. The required second argument specifies the number of elements to delete. The method operates on the array at hand and the return value consists of the array elements deleted.

In the following example the first splice indicates to begin the operation at index 5 and length 2. When the operation completes, the elements f and g have been removed. The second splice indicates a starting position of 2 and length 1. After the operation completes, the letters array has these elements left: a, b, e.
var letters = ["a","b","c","d","e","f","g"];
alert(letters.splice(5, 2));    // => f, g (deleted elements)
alert(letters);                 // => a, b, c, d, e
alert(letters.splice(2, 1));    // => c  (the deleted element)
alert(letters);                 // => a, b, d, e
Run

Using the third argument and higher, the splice method can also be used to replace one or more elements with others. In the example below, the splice starts at position 1 and deletes two elements. Next it replaces the gap with the three elements provided: e, f, g. The final array has 5 elements.

var letters = ["a","b","c","d"];
alert(letters.splice(1, 2, "e", "f", "g")); // => b, c (deleted ones) 
alert(letters);                             // => a, e, f, g, d
Run

You can also use splice() to inject new elements into an array without deleting existing ones. Simply specify a 0 for the second argument, like so:

var letters = ["a","b","e"];
alert(letters.splice(2, 0, "c", "d"));   // => no elements returned
alert(letters);                          // => a,b,c,d,e
Run

Implementing a LIFO stack with push() and pop()

The built-in push() array method appends one or more elements to the end of an array, increments the length as appropriate, and returns the length of the modified array. The built-in pop() array method does the opposite; it deletes the last element, reduces the length by one, and returns the deleted element.

var days = ["Monday"];
alert(days.push("Tuesday", "Wednesday"));   // => 3
alert(days);                       // => Monday, Tuesday, Wednesday
alert(days.pop());                 // => Wednesday
alert(days);                       // => Monday, Tuesday
alert(days.push("Wednesday"));     // => 3
alert(days));                      // => Monday, Tuesday, Wednesday
Run

This code shows that the array methods push() and pop() make it very easy to build a LIFO (last in, first out) stack with JavaScript arrays.

Implementing a FIFO queue with unshift() and shift()

The built-in array method unshift() inserts one or more elements to the beginning of an array, shifts the existing elements up to higher indexes to make space for the new elements, increments the length by the number of elements inserted, and returns the new length. The shift() removes the first element, shifts all the elements with higher indexes down one position to fill the gap, reduces the length by one, and returns value of the element that it removed.

var days = ["Wednesday"];
alert(days.unshift("Monday", "Tuesday"));   // => 3
alert(days)                         // => Monday, Tuesday, Wednesday
alert(days.shift());                // => Monday
alert(days.shift());                // => Tuesday
alert(days);                        // => Wednesday
Run

As you can see, the unshift() and shift() methods make it very easy to build a FIFO (first in, first out) queue with JavaScript arrays.





Manipulating arrays with map(), filter(), reduce()

Three other built-in array methods are map(), filter(), and reduce(). We will discuss each of these.

Transforming array elements with map()

The array method map() is used to change each element in the array and return a new array with the modified elements. For example, you could use map to iterate over an array with numbers and then create a new array in which each element is double the value of the original array. The array returned is of the same length as the original array.

Here's how map() works. Each element of the array on which map() is invoked is passed to a callback function you pass into to map() as an argument. The values returned by the callback are returned in a new array, which is called double in our example below. The original array with the name values on which map() is invoked, is not modified. Since an array is an object, you can also add function methods directly in an array itself.

var values = [1, 2, 3, 4, 5];
alert(values.length);        // => 5
var double = values.map( function (value) {
     return 2 * value;     
});
                       
alert(double);               // => 2, 4, 6, 8, 10
alert(double.length);        // => 5
Run

As you can see, both arrays have the same length. If the values array were a sparse array with missing values, then the double array would also be sparse with gaps in the elements. Both would still be of the same length.





Filtering the array using filter()

Array method reduce() is an accumulator method that iterates over the elements of the array, from left to right, and reduce it to a single value.

The first argument in reduce() is the callback function and the second optional argument is the initial value. The callback function accepts 4 arguments, of which the first 2 are the previous value and the current value. This is best explained with an example.

Say we have a numeric array and we wish to get the sum of all elements. This is how you would do it with reduce():

var values = [2, 4, 6]
var sum = values.reduce(function(prev, curr) { 
        return prev + curr; 
    },            
    0            // initial value
);
alert(sum);       // => 12
Run

When the first callback call is made, the arguments passed to the callback function are 0 (the initial value and second argument to reduce() and 2 (the first element of the array). The function returns 0 + 2 = 2. In the second call, the 2 and 4 are passed and 2 + 4 = 6 is returned. In the last call, 6 and 6 are passed and the final result 12 is returned.

The second argument to reduce() is optional. Had you omitted the 0 in the example above, the first and second elements of the array would have been passed to the function, which also works.