Professional Documents
Culture Documents
18.1. Overview
18.2. New static Array methods
18.2.1. Array.from(arrayLike, mapFunc?, thisArg?)
18.2.2. Array.of(...items)
18.3. New Array.prototype methods
18.3.1. Iterating over Arrays
18.3.2. Searching for Array elements
18.3.3. Array.prototype.copyWithin()
18.3.4. Array.prototype.fill()
18.4. ES6 and holes in Arrays
18.4.1. ECMAScript 6 treats holes like undefined elements
18.4.2. Array operations and holes
18.4.3. Creating Arrays filled with values
18.4.4. Removing holes from Arrays
18.5. Configuring which objects are spread by concat()
(Symbol.isConcatSpreadable)
18.5.1. Default for Arrays: spreading
18.5.2. Default for non-Arrays: no spreading
18.5.3. Detecting Arrays
18.5.4. Symbol.isConcatSpreadable in the standard library
18.6. The numeric range of Array indices
18.1 Overview
Array.from(arrayLike, mapFunc?, thisArg?)
Array.of(...items)
Iterating:
Array.prototype.entries()
Array.prototype.keys()
Array.prototype.values()
Searching for elements:
Array.prototype.find(predicate, thisArg?)
Array.prototype.findIndex(predicate, thisArg?)
Array.prototype.copyWithin(target, start, end=this.length)
Array.prototype.fill(value, start=0, end=this.length)
http://exploringjs.com/es6/ch_arrays.html 1/12
5.12.2018 18. New Array features
const arrayLike = { length: 2, 0: 'a', 1: 'b' };
// forof only works with iterable values
for (const x of arrayLike) { // TypeError
console.log(x);
}
const arr = Array.from(arrayLike);
for (const x of arr) { // OK, iterable
console.log(x);
}
// Output:
// a
// b
const spans = document.querySelectorAll('span.name');
// map(), generically:
const names1 = Array.prototype.map.call(spans, s => s.textContent);
// Array.from():
const names2 = Array.from(spans, s => s.textContent);
http://exploringjs.com/es6/ch_arrays.html 2/12
5.12.2018 18. New Array features
class MyArray extends Array {
18. New Array features
···
Table of contents
} Please support this book: buy it (PDF, EPUB, MOBI) or donate
const instanceOfMyArray = MyArray.from(anIterable);
You can also combine this functionality with mapping, to get a map operation
where you control the result’s constructor:
// from() – determine the result’s constructor via the receiver
// (in this case, MyArray)
const instanceOfMyArray = MyArray.from([1, 2, 3], x => x * x);
// map(): the result is always an instance of Array
const instanceOfArray = [1, 2, 3].map(x => x * x);
The species pattern lets you configure what instances non-static built-in
methods (such as slice(), filter() and map()) return. It is explained in Sect.
“The species pattern” in Chap. “Classes”.
18.2.2 Array.of(...items)
If you want to turn several values into an Array, you should always use an Array
literal, especially since the Array constructor doesn’t work properly if there is a
single value that is a number (more information on this quirk):
> new Array(3, 11, 8)
[ 3, 11, 8 ]
> new Array(3)
[ , , ,]
> new Array(3.1)
RangeError: Invalid array length
But how are you supposed to turn values into an instance of a sub-constructor
of Array then? This is where Array.of() helps (remember that sub-constructors
of Array inherit all of Array’s methods, including of()).
class MyArray extends Array {
···
}
console.log(MyArray.of(3, 11, 8) instanceof MyArray); // true
console.log(MyArray.of(3).length === 1); // true
Array.prototype.entries()
Array.prototype.keys()
http://exploringjs.com/es6/ch_arrays.html 3/12
5.12.2018 18. New Array features
I could also have used the spread operator (...) to convert iterators to Arrays:
> [...['a', 'b'].keys()]
[ 0, 1 ]
You can combine entries() with ECMAScript 6’s forof loop and destructuring
to conveniently iterate over [index, element] pairs:
for (const [index, element] of ['a', 'b'].entries()) {
console.log(index, element);
}
Array.prototype.find(predicate, thisArg?)
Returns the first Array element for which the callback predicate returns true. If
there is no such element, it returns undefined. Example:
> [6, 5, 8].find(x => x < 0)
5
> [6, 5, 8].find(x => x < 0)
undefined
Array.prototype.findIndex(predicate, thisArg?)
Returns the index of the first element for which the callback predicate returns
true. If there is no such element, it returns 1. Example:
> [6, 5, 8].findIndex(x => x < 0)
1
> [6, 5, 8].findIndex(x => x < 0)
1
http://exploringjs.com/es6/ch_arrays.html 4/12
5.12.2018 18. New Array features
> [NaN].indexOf(NaN)
18. New Array features
1
Table of contents
Please support this book: buy it (PDF, EPUB, MOBI) or donate
With findIndex(), you can use Object.is() (explained in the chapter on OOP)
and will have no such problem:
> [NaN].findIndex(y => Object.is(NaN, y))
0
You can also adopt a more general approach, by creating a helper function
elemIs():
> function elemIs(x) { return Object.is.bind(Object, x) }
> [NaN].findIndex(elemIs(NaN))
0
18.3.3 Array.prototype.copyWithin()
Array.prototype.copyWithin(target : number,
start : number, end = this.length) : This
It copies the elements whose indices are in the range [start,end) to index
target and subsequent indices. If the two index ranges overlap, care is taken
that all source elements are copied before they are overwritten.
Example:
> const arr = [0,1,2,3];
> arr.copyWithin(2, 0, 2)
[ 0, 1, 0, 1 ]
> arr
[ 0, 1, 0, 1 ]
18.3.4 Array.prototype.fill()
Optionally, you can restrict where the filling starts and ends:
> ['a', 'b', 'c'].fill(7, 1, 2)
[ 'a', 7, 'c' ]
Holes are indices “inside” an Array that have no associated element. In other
words: An Array arr is said to have a hole at index i if:
http://exploringjs.com/es6/ch_arrays.html 5/12
5.12.2018 18. New Array features
You’ll see lots of examples involving holes in this section. Should anything ever
be unclear, you can consult Sect. “Holes in Arrays” in “Speaking JavaScript” for
more information.
ES6 pretends that holes don’t exist (as much as it can while being backward-
compatible). And so should you – especially if you consider that holes can also
affect performance negatively. Then you don’t have to burden your brain with
the numerous and inconsistent rules around holes.
The general rule for Array methods that are new in ES6 is: each hole is treated
as if it were the element undefined. Examples:
> Array.from(['a',,'b'])
[ 'a', undefined, 'b' ]
> [,'a'].findIndex(x => x === undefined)
0
> [...[,'a'].entries()]
[ [ 0, undefined ], [ 1, 'a' ] ]
The idea is to steer people away from holes and to simplify long-term.
Unfortunately that means that things are even more inconsistent now.
18.4.2.1 Iteration
If we invoke next() twice, we get the hole at index 0 and the element 'a' at
index 1. As you can see, the former produces undefined:
> iter.next()
{ value: undefined, done: false }
> iter.next()
{ value: 'a', done: false }
http://exploringjs.com/es6/ch_arrays.html 6/12
5.12.2018 18. New Array features
for (const x of [, 'a']) {
console.log(x);
}
// Output:
// undefined
// a
Note that the Array prototype methods (filter() etc.) do not use the iteration
protocol.
18.4.2.2 Array.from()
> Array.from([, 'a'])
[ undefined, 'a' ]
But Array.from() can also convert Array-like objects to Arrays. Then holes
become undefined, too:
> Array.from({1: 'a', length: 2})
[ undefined, 'a' ]
> [,'a'].map(x => x)
[ , 'a' ]
> [,'a'].map((x,i) => i)
[ , 1 ]
http://exploringjs.com/es6/ch_arrays.html 7/12
5.12.2018 18. New Array features
http://exploringjs.com/es6/ch_arrays.html 8/12
5.12.2018 18. New Array features
Holes being treated as undefined elements by the new ES6 operations helps
with creating Arrays that are filled with values.
> new Array(3).fill(7)
[ 7, 7, 7 ]
new Array(3) creates an Array with three holes and fill() replaces each hole
with the value 7.
> [...new Array(3).keys()]
[ 0, 1, 2 ]
> Array.from(new Array(5), (x,i) => i*2)
[ 0, 2, 4, 6, 8 ]
If you need an Array that is filled with undefined, you can use the fact that
iteration (as triggered by the spread operator) converts holes to undefineds:
> [...new Array(3)]
[ undefined, undefined, undefined ]
http://exploringjs.com/es6/ch_arrays.html 9/12
5.12.2018 18. New Array features
const arr1 = ['c', 'd'];
['a', 'b'].concat(arr1, 'e');
// ['a', 'b', 'c', 'd', 'e']
const arr2 = ['c', 'd'];
arr2[Symbol.isConcatSpreadable] = false;
['a', 'b'].concat(arr2, 'e');
// ['a', 'b', ['c','d'], 'e']
const arrayLike = {length: 2, 0: 'c', 1: 'd'};
console.log(['a', 'b'].concat(arrayLike, 'e'));
// ['a', 'b', arrayLike, 'e']
console.log(Array.prototype.concat.call(
arrayLike, ['e','f'], 'g'));
// [arrayLike, 'e', 'f', 'g']
arrayLike[Symbol.isConcatSpreadable] = true;
console.log(['a', 'b'].concat(arrayLike, 'e'));
// ['a', 'b', 'c', 'd', 'e']
console.log(Array.prototype.concat.call(
arrayLike, ['e','f'], 'g'));
// ['c', 'd', 'e', 'f', 'g']
http://exploringjs.com/es6/ch_arrays.html 10/12
5.12.2018 18. New Array features
> const arr = [];
> Array.isArray(arr)
true
> Object.setPrototypeOf(arr, null);
> Array.isArray(arr)
true
No object in the ES6 standard library has a property with the key
Symbol.isConcatSpreadable. This mechanism therefore exists purely for
browser APIs and user code.
Consequences:
Strings and Typed Arrays have a larger range of indices: 0 ≤ i < 253−1. The
upper bound of that range is due to 253−1 being the largest integer that
http://exploringjs.com/es6/ch_arrays.html 11/12
5.12.2018 18. New Array features
Generic Array methods such as push() and unshift() allow the larger range of
indices. Range checks appropriate for Arrays are performed elsewhere,
whenever length is set.
http://exploringjs.com/es6/ch_arrays.html 12/12