Chapter 18. Arrays

## Chapter 18. Arrays

An array is a map from indices (natural numbers, starting at zero) to arbitrary values. The values (the range of the map) are called the array’s elements. The most convenient way of creating an array is via an array literal. Such a literal enumerates the array elements; an element’s position implicitly specifies its index.

In this chapter, I will first cover basic array mechanisms, such as indexed access and the `length` property, and then go over array methods.

## Overview

This section provides a quick overview of arrays. Details are explained later.

As a first example, we create an array `arr` via an array literal (see Creating Arrays) and access elements (see Array Indices):

```> var arr = [ 'a', 'b', 'c' ]; // array literal
> arr  // get element 0
'a'
> arr = 'x';  // set element 0
> arr
[ 'x', 'b', 'c' ]```

We can use the array property `length` (see length) to remove and append elements:

```> var arr = [ 'a', 'b', 'c' ];
> arr.length
3
> arr.length = 2;  // remove an element
> arr
[ 'a', 'b' ]
> arr[arr.length] = 'd';  // append an element
> arr
[ 'a', 'b', 'd' ]```

The array method `push()` provides another way of appending an element:

```> var arr = [ 'a', 'b' ];
> arr.push('d')
3
> arr
[ 'a', 'b', 'd' ]```

### Arrays Are Maps, Not Tuples

The ECMAScript standard specifies arrays as maps (dictionaries) from indices to values. In other words, arrays may not be contiguous and can have holes in them. For example:

```> var arr = [];
> arr = 'a';
'a'
> arr = 'b';
'b'
> arr
[ 'a', , 'b' ]```

The preceding array has a hole: there is no element at index 1. Holes in Arrays explains holes in more detail.

Note that most JavaScript engines optimize arrays without holes internally and store them contiguously.

### Arrays Can Also Have Properties

```> var arr = [ 'a', 'b' ];
> arr.foo = 123;
> arr
[ 'a', 'b' ]
> arr.foo
123```

## Creating Arrays

You create an array via an array literal:

``var` `myArray` `=` `[` `'a'``,` `'b'``,` `'c'` `];``

Trailing commas in arrays are ignored:

```> [ 'a', 'b' ].length
2
> [ 'a', 'b', ].length
2
> [ 'a', 'b', ,].length  // hole + trailing comma
3```

### The Array Constructor

#### Creating an empty array with a given length

```> var arr = new Array(2);
> arr.length
2
> arr  // two holes plus trailing comma (ignored!)
[ , ,]```

Some engines may preallocate contiguous memory when you call `Array()` in this manner, which may slightly improve performance. However, be sure that the increased verbosity and redundancy is worth it!

#### Initializing an array with elements (avoid!)

````// The same as ['a', 'b', 'c']:`
`var` `arr1` `=` `new` `Array``(``'a'``,` `'b'``,` `'c'``);````

The problem is that you can’t create arrays with a single number in them, because that is interpreted as creating an array whose `length` is the number:

```> new Array(2)  // alas, not [ 2 ]
[ , ,]

> new Array(5.7)  // alas, not [ 5.7 ]
RangeError: Invalid array length

> new Array('abc')  // ok
[ 'abc' ]```

### Multidimensional Arrays

````// Create the Tic-tac-toe board`
`var` `rows` `=` `[];`
`for` `(``var` `rowCount``=``0``;` `rowCount` `<` `3``;` `rowCount``++``)` `{`
`rows``[``rowCount``]` `=` `[];`
`for` `(``var` `colCount``=``0``;` `colCount` `<` `3``;` `colCount``++``)` `{`
`rows``[``rowCount``][``colCount``]` `=` `'.'``;`
`}`
`}`

`// Set an X in the upper right corner`
`rows``[``0``][``2``]` `=` `'X'``;`  `// [row][column]`

`// Print the board`
`rows``.``forEach``(``function` `(``row``)` `{`
`console``.``log``(``row``.``join``(``' '``));`
`});````

Here is the output:

```. . X
. . .
. . .```

I wanted the example to demonstrate the general case. Obviously, if a matrix is so small and has fixed dimensions, you can set it up via an array literal:

``var` `rows` `=` `[` `[``'.'``,``'.'``,``'.'``],` `[``'.'``,``'.'``,``'.'``],` `[``'.'``,``'.'``,``'.'``]` `];``

## Array Indices

When you are working with array indices, you must keep in mind the following limits:

• Indices are numbers i in the range 0 ≤ i < 232−1.
• The maximum length is 232−1.

Indices that are out of range are treated as normal property keys (strings!). They don’t show up as array elements and they don’t influence the property `length`. For example:

```> var arr = [];

> arr[-1] = 'a';
> arr
[]
> arr['-1']
'a'

> arr = 'b';
> arr
[]
> arr['4294967296']
'b'```

### The in Operator and Indices

```> var arr = [ 'a', , 'b' ];
> 0 in arr
true
> 1 in arr
false
> 10 in arr
false```

### Deleting Array Elements

In addition to deleting properties, the `delete` operator also deletes array elements. Deleting elements creates holes (the `length` property is not updated):

```> var arr = [ 'a', 'b' ];
> arr.length
2
> delete arr  // does not update length
true
> arr
[ 'a',  ]
> arr.length
2```

You can also delete trailing array elements by decreasing an array’s length (see length for details). To remove elements without creating holes (i.e., the indices of subsequent elements are decremented), you use `Array.prototype.splice()` (see Adding and Removing Elements (Destructive)). In this example, we remove two elements at index 1:

```> var arr = ['a', 'b', 'c', 'd'];
> arr.splice(1, 2) // returns what has been removed
[ 'b', 'c' ]
> arr
[ 'a', 'd' ]```

### Tip

This is an advanced section. You normally don’t need to know the details explained here.

Array indices are not what they seem. Until now, I have pretended that array indices are numbers. And that is how JavaScript engines implement arrays, internally. However, the ECMAScript specification sees indices differently. Paraphrasing Section 15.4:

• A property key `P` (a string) is an array index if and only if `ToString``(ToUint32(P))` is equal to `P` and `ToUint32(P)` is not equal to 232−1. What this means is explained momentarily.
• An array property whose key is an array index is called an element.

In other words, in the world of the spec all values in brackets are converted to strings and interpreted as property keys, even numbers. The following interaction demonstrates this:

```> var arr = ['a', 'b'];
> arr['0']
'a'
> arr
'a'```

To be an array index, a property key `P` (a string!) must be equal to the result of the following computation:

1. Convert `P` to a number.
2. Convert the number to a 32-bit unsigned integer.
3. Convert the integer to a string.

That means that an array index must be a stringified integer i in the 32-bit range 0 ≤ i < 232−1. The upper limit has been explicitly excluded in the spec (as quoted previously). It is reserved for the maximum length. To see how this definition works, let’s use the function `ToUint32()` from 32-bit Integers via Bitwise Operators.

First, a string that doesn’t contain a number is always converted to 0, which, after stringification, is not equal to the string:

```> ToUint32('xyz')
0
> ToUint32('?@#!')
0```

Second, a stringified integer that is out of range is also converted to a completely different integer, which is not equal to the string, after stringification:

```> ToUint32('-1')
4294967295
> Math.pow(2, 32)
4294967296
> ToUint32('4294967296')
0```

Third, stringified noninteger numbers are converted to integers, which are, again, different:

```> ToUint32('1.371')
1```

Note that the specification also enforces that array indices don’t have exponents:

```> ToUint32('1e3')
1000```

And that they don’t have leading zeros:

```> var arr = ['a', 'b'];
> arr['0']  // array index
'a'
> arr['00'] // normal property
undefined```

## length

The basic function of the `length` property is to track the highest index in an array:

```> [ 'a', 'b' ].length
2
> [ 'a', , 'b' ].length
3```

Thus, `length` does not count the number of elements, so you’d have to write your own function for doing so. For example:

````function` `countElements``(``arr``)` `{`
`var` `elemCount` `=` `0``;`
`arr``.``forEach``(``function` `()` `{`
`elemCount``++``;`
`});`
`return` `elemCount``;`
`}````

To count elements (nonholes), we have used the fact that `forEach` skips holes. Here is the interaction:

```> countElements([ 'a', 'b' ])
2
> countElements([ 'a', , 'b' ])
2```

### Manually Increasing the Length of an Array

Manually increasing the length of an array has remarkably little effect on an array; it only creates holes:

```> var arr = [ 'a', 'b' ];
> arr.length = 3;
> arr  // one hole at the end
[ 'a', 'b', ,]```

The last result has two commas at the end, because a trailing comma is optional and thus always ignored.

What we just did did not add any elements:

```> countElements(arr)
2```

However, the `length` property does act as a pointer indicating where to insert new elements. For example:

```> arr.push('c')
4
> arr
[ 'a', 'b', , 'c' ]```

Thus, setting the initial length of an array via the `Array` constructor creates an array that is completely empty:

```> var arr = new Array(2);
> arr.length
2
> countElements(arr)
0```

### Decreasing the Length of an Array

If you decrease the length of an array, all elements at the new length and above are deleted:

```> var arr = [ 'a', 'b', 'c' ];
> 1 in arr
true
> arr
'b'

> arr.length = 1;
> arr
[ 'a' ]
> 1 in arr
false
> arr
undefined```

#### Clearing an array

If you set an array’s length to 0, then it becomes empty. That allows you to clear an array for someone else. For example:

````function` `clearArray``(``arr``)` `{`
`arr``.``length` `=` `0``;`
`}````

Here’s the interaction:

```> var arr = [ 'a', 'b', 'c' ];
> clearArray(arr)
> arr
[]```

Note, however, that this approach can be slow, because each array element is explicitly deleted. Ironically, creating a new empty array is often faster:

``arr` `=` `[];``

#### Clearing shared arrays

You need to be aware of the fact that setting an array’s length to zero affects everybody who shares the array:

````>` `var` `a1` `=` `[``1``,` `2``,` `3``];`
`>` `var` `a2` `=` `a1``;`
`>` `a1``.``length` `=` `0``;`

`>` `a1`
`[]`
`>` `a2`
`[]````

In contrast, assigning an empty array doesn’t:

````>` `var` `a1` `=` `[``1``,` `2``,` `3``];`
`>` `var` `a2` `=` `a1``;`
`>` `a1` `=` `[];`

`>` `a1`
`[]`
`>` `a2`
`[` `1``,` `2``,` `3` `]````

### The Maximum Length

The maximum array length is 232−1:

```> var arr1 = new Array(Math.pow(2, 32));  // not ok
RangeError: Invalid array length

> var arr2 = new Array(Math.pow(2, 32)-1);  // ok
> arr2.push('x');
RangeError: Invalid array length```

## Holes in Arrays

Arrays are maps from indices to values. That means that arrays can have holes, indices smaller than the length that are missing in the array. Reading an element at one of those indices returns `undefined`.

### Tip

It is recommended that you avoid holes in arrays. JavaScript handles them inconsistently (i.e., some methods ignore them, other don’t). Thankfully, you normally don’t need to know how holes are handled: they are rarely useful and affect performance negatively.

### Creating Holes

You can create holes by assigning to array indices:

```> var arr = [];
> arr = 'a';
> arr = 'c';
> 1 in arr  // hole at index 1
false```

You can also create holes by omitting values in array literals:

```> var arr = ['a',,'c'];
> 1 in arr  // hole at index 1
false```

### Warning

You need two trailing commas to create a trailing hole, because the last comma is always ignored:

```> [ 'a', ].length
1
> [ 'a', ,].length
2```

### Sparse Arrays Versus Dense Arrays

This section examines the differences between a hole and `undefined` as an element. Given that reading a hole returns `undefined`, both are very similar.

````var` `sparse` `=` `[` `,` `,` `'c'` `];`
`var` `dense`  `=` `[` `undefined``,` `undefined``,` `'c'` `];````

A hole is almost like having the element `undefined` at the same index. Both arrays have the same length:

```> sparse.length
3
> dense.length
3```

But the sparse array does not have an element at index 0:

```> 0 in sparse
false
> 0 in dense
true```

Iteration via `for` is the same for both arrays:

```> for (var i=0; i<sparse.length; i++) console.log(sparse[i]);
undefined
undefined
c
> for (var i=0; i<dense.length; i++) console.log(dense[i]);
undefined
undefined
c```

Iteration via `forEach` skips the holes, but not the undefined elements:

```> sparse.forEach(function (x) { console.log(x) });
c
> dense.forEach(function (x) { console.log(x) });
undefined
undefined
c```

### Which Operations Ignore Holes, and Which Consider Them?

Some operations involving arrays ignore holes, while others consider them. This sections explains the details.

#### Array iteration methods

`forEach()` skips holes:

```> ['a',, 'b'].forEach(function (x,i) { console.log(i+'.'+x) })
0.a
2.b```

`every()` also skips holes (similarly: `some()`):

```> ['a',, 'b'].every(function (x) { return typeof x === 'string' })
true```

`map()` skips, but preserves holes:

```> ['a',, 'b'].map(function (x,i) { return i+'.'+x })
[ '0.a', , '2.b' ]```

`filter()` eliminates holes:

```> ['a',, 'b'].filter(function (x) { return true })
[ 'a', 'b' ]```

#### Other array methods

`join()` converts holes, `undefined`s, and `null`s to empty strings:

```> ['a',, 'b'].join('-')
'a--b'
> [ 'a', undefined, 'b' ].join('-')
'a--b'```

`sort()` preserves holes while sorting:

```> ['a',, 'b'].sort()  // length of result is 3
[ 'a', 'b', ,  ]```

#### The for-in loop

The `for-in` loop correctly lists property keys (which are a superset of array indices):

```> for (var key in ['a',, 'b']) { console.log(key) }
0
2```

#### Function.prototype.apply()

`apply()` turns each hole into an argument whose value is `undefined`. The following interaction demonstrates this: function `f()` returns its arguments as an array. When we pass `apply()` an array with three holes in order to invoke `f()`, the latter receives three `undefined` arguments:

```> function f() { return [].slice.call(arguments) }
> f.apply(null, [ , , ,])
[ undefined, undefined, undefined ]```

That means that we can use `apply()` to create an array with `undefined`s:

```> Array.apply(null, Array(3))
[ undefined, undefined, undefined ]```

### Warning

`apply()` translates holes to `undefined`s in empty arrays, but it can’t be used to plug holes in arbitrary arrays (which may or may not contain holes). Take, for example, the arbitrary array ``:

```> Array.apply(null, )
[ , ,]```

The array does not contain any holes, so `apply()` should return the same array. Instead, it returns an empty array with length 2 (all it contains are two holes). That is because `Array()` interprets single numbers as array lengths, not as array elements.

### Removing Holes from Arrays

As we have seen, `filter()` removes holes:

```> ['a',, 'b'].filter(function (x) { return true })
[ 'a', 'b' ]```

Use a custom function to convert holes to `undefined`s in arbitrary arrays:

````function` `convertHolesToUndefineds``(``arr``)` `{`
`var` `result` `=` `[];`
`for` `(``var` `i``=``0``;` `i` `<` `arr``.``length``;` `i``++``)` `{`
`result``[``i``]` `=` `arr``[``i``];`
`}`
`return` `result``;`
`}````

Using the function:

```> convertHolesToUndefineds(['a',, 'b'])
[ 'a', undefined, 'b' ]```

## Adding and Removing Elements (Destructive)

All of the methods in this section are destructive:

`Array.prototype.shift()`
```> var arr = [ 'a', 'b' ];
> arr.shift()
'a'
> arr
[ 'b' ]```
`Array.prototype.unshift(elem1?, elem2?, ...)`
```> var arr = [ 'c', 'd' ];
> arr.unshift('a', 'b')
4
> arr
[ 'a', 'b', 'c', 'd' ]```
`Array.prototype.pop()`

Removes the last element of the array and returns it:

```> var arr = [ 'a', 'b' ];
> arr.pop()
'b'
> arr
[ 'a' ]```
`Array.prototype.push(elem1?, elem2?, ...)`

Adds the given elements to the end of the array. It returns the new length:

```> var arr = [ 'a', 'b' ];
> arr.push('c', 'd')
4
> arr
[ 'a', 'b', 'c', 'd' ]```
```> var arr1 = [ 'a', 'b' ];
> var arr2 = [ 'c', 'd' ];

> Array.prototype.push.apply(arr1, arr2)
4
> arr1
[ 'a', 'b', 'c', 'd' ]```
`Array.prototype.splice(start, deleteCount?, elem1?, elem2?, ...)`
```> var arr = [ 'a', 'b', 'c', 'd' ];
> arr.splice(1, 2, 'X');
[ 'b', 'c' ]
> arr
[ 'a', 'X', 'd' ]```

Special parameter values:

• `start` can be negative, in which case it is added to the length to determine the start index. Thus, `-1` refers the last element, and so on.
• `deleteCount` is optional. If it is omitted (along with all subsequent arguments), then all elements at and after index `start` are removed.

In this example, we remove all elements after and including the second-to-last index:

```> var arr = [ 'a', 'b', 'c', 'd' ];
> arr.splice(-2)
[ 'c', 'd' ]
> arr
[ 'a', 'b' ]```

## Sorting and Reversing Elements (Destructive)

These methods are also destructive:

`Array.prototype.reverse()`
```> var arr = [ 'a', 'b', 'c' ];
> arr.reverse()
[ 'c', 'b', 'a' ]
> arr // reversing happened in place
[ 'c', 'b', 'a' ]```
`Array.prototype.sort(compareFunction?)`
```> var arr = ['banana', 'apple', 'pear', 'orange'];
> arr.sort()
[ 'apple', 'banana', 'orange', 'pear' ]
> arr  // sorting happened in place
[ 'apple', 'banana', 'orange', 'pear' ]```

Keep in mind that sorting compares values by converting them to strings, which means that numbers are not sorted numerically:

```> [-1, -20, 7, 50].sort()
[ -1, -20, 50, 7 ]```

You can fix this by providing the optional parameter `compareFunction`, which controls how sorting is done. It has the following signature:

``function` `compareFunction``(``a``,` `b``)``

This function compares `a` and `b` and returns:

• An integer less than zero (e.g., `-1`) if `a` is less than `b`
• Zero if `a` is equal to `b`
• An integer greater than zero (e.g., `1`) if `a` is greater than `b`

### Comparing Numbers

````function` `compareCanonically``(``a``,` `b``)` `{`
`if` `(``a` `<` `b``)` `{`
`return` `-``1``;`
`}` `else` `if` `(``a` `>` `b``)` `{`
`return` `1``;`
`}` `else` `{`
`return` `0``;`
`}`
`}````

I don’t like nested conditional operators. But in this case, the code is so much less verbose that I’m tempted to recommend it:

````function` `compareCanonically``(``a``,` `b``)` `{`
`return` `a` `<` `b` `?` `-``1` `:` `(``a` `>` `b` `?` `1` `:` `0``);`
`}````

Using the function:

```> [-1, -20, 7, 50].sort(compareCanonically)
[ -20, -1, 7, 50 ]```

### Comparing Strings

For strings, you can use `String.prototype.localeCompare` (see Comparing Strings):

```> ['c', 'a', 'b'].sort(function (a,b) { return a.localeCompare(b) })
[ 'a', 'b', 'c' ]```

### Comparing Objects

The parameter `compareFunction` is also useful for sorting objects:

````var` `arr` `=` `[`
`{` `name``:` `'Tarzan'` `},`
`{` `name``:` `'Cheeta'` `},`
`{` `name``:` `'Jane'` `}` `];`

`function` `compareNames``(``a``,``b``)` `{`
`return` `a``.``name``.``localeCompare``(``b``.``name``);`
`}````

With `compareNames` as the compare function, `arr` is sorted by `name`:

```> arr.sort(compareNames)
[ { name: 'Cheeta' },
{ name: 'Jane' },
{ name: 'Tarzan' } ]```

## Concatenating, Slicing, Joining (Nondestructive)

`Array.prototype.concat(arr1?, arr2?, ...)`
```> var arr = [ 'a', 'b' ];
> arr.concat('c', ['d', 'e'])
[ 'a', 'b', 'c', 'd', 'e' ]```

The array that `concat()` is invoked on is not changed:

```> arr
[ 'a', 'b' ]```
`Array.prototype.slice(begin?, end?)`
```> [ 'a', 'b', 'c', 'd' ].slice(1, 3)
[ 'b', 'c' ]```

If `end` is missing, the array length is used:

```> [ 'a', 'b', 'c', 'd' ].slice(1)
[ 'b', 'c', 'd' ]```

If both indices are missing, the array is copied:

```> [ 'a', 'b', 'c', 'd' ].slice()
[ 'a', 'b', 'c', 'd' ]```

If either of the indices is negative, the array length is added to it. Thus, `-1` refers to the last element, and so on:

```> [ 'a', 'b', 'c', 'd' ].slice(1, -1)
[ 'b', 'c' ]
> [ 'a', 'b', 'c', 'd' ].slice(-2)
[ 'c', 'd' ]```
`Array.prototype.join(separator?)`
```> [3, 4, 5].join('-')
'3-4-5'
> [3, 4, 5].join()
'3,4,5'
> [3, 4, 5].join('')
'345'```

`join()` converts `undefined` and `null` to empty strings:

```> [undefined, null].join('#')
'#'```

Holes in arrays are also converted to empty strings:

```> ['a',, 'b'].join('-')
'a--b'```

## Searching for Values (Nondestructive)

The following methods search for values in arrays:

`Array.prototype.indexOf(searchValue, startIndex?)`
```> [ 3, 1, 17, 1, 4 ].indexOf(1)
1
> [ 3, 1, 17, 1, 4 ].indexOf(1, 2)
3```

Strict equality (see Equality Operators: === Versus ==) is used for the search, which means that `indexOf()` can’t find `NaN`:

```> [NaN].indexOf(NaN)
-1```
`Array.prototype.lastIndexOf(searchElement, startIndex?)`
```> [ 3, 1, 17, 1, 4 ].lastIndexOf(1)
3
> [ 3, 1, 17, 1, 4 ].lastIndexOf(1, -3)
1```

## Iteration (Nondestructive)

### Examination Methods

Each method described in this section looks like this:

``arr``.``examinationMethod``(``callback``,` `thisValue``?``)``

Such a method takes the following parameters:

• `callback` is its first parameter, a function that it calls. Depending on the examination method, the callback returns a boolean or nothing. It has the following signature:

``function` `callback``(``element``,` `index``,` `array``)``

`element` is an array element for `callback` to process, `index` is the element’s index, and `array` is the array that `examinationMethod` has been invoked on.

• `thisValue` allows you to configure the value of `this` inside `callback`.

And now for the examination methods whose signatures I have just described:

`Array.prototype.forEach(callback, thisValue?)`

Iterates over the elements of an array:

````var` `arr` `=` `[` `'apple'``,` `'pear'``,` `'orange'` `];`
`arr``.``forEach``(``function` `(``elem``)` `{`
`console``.``log``(``elem``);`
`});````
`Array.prototype.every(callback, thisValue?)`

This example checks whether every number in the array is even:

```> function isEven(x) { return x % 2 === 0 }
> [ 2, 4, 6 ].every(isEven)
true
> [ 2, 3, 4 ].every(isEven)
false```

If the array is empty, the result is `true` (and `callback` is not called):

```> [].every(function () { throw new Error() })
true```
`Array.prototype.some(callback, thisValue?)`

This example checks whether there is an even number in the array:

```> function isEven(x) { return x % 2 === 0 }
> [ 1, 3, 5 ].some(isEven)
false
> [ 1, 2, 3 ].some(isEven)
true```

If the array is empty, the result is `false` (and `callback` is not called):

```> [].some(function () { throw new Error() })
false```

One potential pitfall of `forEach()` is that it does not support `break` or something similar to prematurely abort the loop. If you need to do that, you can use `some()`:

````function` `breakAtEmptyString``(``strArr``)` `{`
`strArr``.``some``(``function` `(``elem``)` `{`
`if` `(``elem``.``length` `===` `0``)` `{`
`return` `true``;` `// break`
`}`
`console``.``log``(``elem``);`
`// implicit: return undefined (interpreted as false)`
`});`
`}````

`some()` returns `true` if a break happened, and `false` otherwise. This allows you to react differently depending on whether iterating finished successfully (something that is slightly tricky with `for` loops).

### Transformation Methods

``function` `callback``(``element``,` `index``,` `array``)``

There are two transformation methods:

`Array.prototype.map(callback, thisValue?)`

Each output array element is the result of applying `callback` to an input element. For example:

```> [ 1, 2, 3 ].map(function (x) { return 2 * x })
[ 2, 4, 6 ]```
`Array.prototype.filter(callback, thisValue?)`
```> [ 1, 0, 3, 0 ].filter(function (x) { return x !== 0 })
[ 1, 3 ]```

### Reduction Methods

For reducing, the callback has a different signature:

``function` `callback``(``previousValue``,` `currentElement``,` `currentIndex``,` `array``)``

The parameter `previousValue` is the value previously returned by the callback. When the callback is first called, there are two possibilities (the descriptions are for `Array.prototype.reduce()`; differences with `reduceRight()` are mentioned in parentheses):

• An explicit `initialValue` has been provided. Then `previousValue` is `initialValue`, and `currentElement` is the first array element (`reduceRight`: the last array element).
• No explicit `initialValue` has been provided. Then `previousValue` is the first array element, and `currentElement` is the second array element (`reduceRight`: the last array element and second-to-last array element).

There are two reduction methods:

`Array.prototype.reduce(callback, initialValue?)`
````function` `add``(``prev``,` `cur``)` `{`
`return` `prev` `+` `cur``;`
`}`
`console``.``log``([``10``,` `3``,` `-``1``].``reduce``(``add``));` `// 12````

If you invoke `reduce` on an array with a single element, that element is returned:

```> .reduce(add)
7```

If you invoke `reduce` on an empty array, you must specify `initialValue`, otherwise you get an exception:

```> [].reduce(add)
TypeError: Reduce of empty array with no initial value
123```
`Array.prototype.reduceRight(callback, initialValue?)`
Works the same as `reduce()`, but iterates from right to left.

### Note

In many functional programming languages, `reduce` is known as `fold` or `foldl` (left fold) and `reduceRight` is known as `foldr` (right fold).

Another way to look at the `reduce` method is that it implements an n-ary operator `OP`:

`OP1≤i≤n` xi

via a series of applications of a binary operator `op2`:

(...(x1 `op2` x2) `op2` ...) `op2` xn

That’s what happened in the previous code example: we implemented an n-ary sum operator for arrays via JavaScript’s binary plus operator.

As an example, let’s examine the two iteration directions via the following function:

````function` `printArgs``(``prev``,` `cur``,` `i``)` `{`
`console``.``log``(``'prev:'``+``prev``+``', cur:'``+``cur``+``', i:'``+``i``);`
`return` `prev` `+` `cur``;`
`}````

As expected, `reduce()` iterates from left to right:

```> ['a', 'b', 'c'].reduce(printArgs)
prev:a, cur:b, i:1
prev:ab, cur:c, i:2
'abc'
> ['a', 'b', 'c'].reduce(printArgs, 'x')
prev:x, cur:a, i:0
prev:xa, cur:b, i:1
prev:xab, cur:c, i:2
'xabc'```

And `reduceRight()` iterates from right to left:

```> ['a', 'b', 'c'].reduceRight(printArgs)
prev:c, cur:b, i:1
prev:cb, cur:a, i:0
'cba'
> ['a', 'b', 'c'].reduceRight(printArgs, 'x')
prev:x, cur:c, i:2
prev:xc, cur:b, i:1
prev:xcb, cur:a, i:0
'xcba'```

## Best Practices: Iterating over Arrays

• A simple `for` loop (see for):

````for` `(``var` `i``=``0``;` `i``<``arr``.``length``;` `i``++``)` `{`
`console``.``log``(``arr``[``i``]);`
`}````
• One of the array iteration methods (see Iteration (Nondestructive)). For example, `forEach()`:

````arr``.``forEach``(``function` `(``elem``)` `{`
`console``.``log``(``elem``);`
`});````

Do not use the `for-in` loop (see for-in) to iterate over arrays. It iterates over indices, not over values. And it includes the keys of normal properties while doing so, including inherited ones.