Array
メソッドArray.from(arrayLike, mapFunc?, thisArg?)
Array.of(...items)
Array.prototype
メソッドArray.prototype.copyWithin()
Array.prototype.fill()
undefined
要素のように扱うconcat()
で展開するかを設定する(Symbol.isConcatSpreadable
)Symbol.isConcatSpreadable
新しい静的Array
メソッド
Array.from(arrayLike, mapFunc?, thisArg?)
Array.of(...items)
新しいArray.prototype
メソッド
Array.prototype.entries()
Array.prototype.keys()
Array.prototype.values()
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)
Array
メソッド オブジェクトArray
には新しいメソッドがあります。
Array.from(arrayLike, mapFunc?, thisArg?)
Array.from()
の基本的な機能は、2種類の値を配列に変換することです。
length
プロパティとインデックス付き要素を持っています。例として、document.getElementsByClassName()
などのDOM操作の結果があります。Map
とSet
も同様です。以下は、配列のようなオブジェクトを配列に変換する例です。
const
arrayLike
=
{
length
:
2
,
0
:
'a'
,
1
:
'b'
};
// for-of 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
Array.from()
によるマッピング Array.from()
は、map()
をジェネリックに使用する便利な代替手段でもあります。
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
);
この例では、document.querySelectorAll()
の結果は、再び配列ではなく配列のようなオブジェクトであるため、map()
を呼び出すことができませんでした。以前は、forEach()
を呼び出すために、配列のようなオブジェクトを配列に変換していました。ここでは、ジェネリックメソッド呼び出しとArray.from()
の2パラメータバージョンを使用して、その中間ステップをスキップしました。
from()
Array.from()
のもう1つのユースケースは、配列のような値または反復可能な値をArray
のサブクラスのインスタンスに変換することです。たとえば、Array
のサブクラスMyArray
を作成し、そのようなオブジェクトをMyArray
のインスタンスに変換する場合は、MyArray.from()
を使用するだけです。それが機能する理由は、コンストラクターがECMAScript 6で互いに継承する(スーパコンストラクターはサブコンストラクターのプロトタイプである)ためです。
class
MyArray
extends
Array
{
···
}
const
instanceOfMyArray
=
MyArray
.
from
(
anIterable
);
この機能をマッピングと組み合わせて、結果のコンストラクターを制御するマップ操作を取得することもできます。
// 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
);
種パターンを使用すると、非静的組み込みメソッド(slice()
、filter()
、map()
など)が返すインスタンスを構成できます。これは、「クラス」の章の「種パターン」で説明されています。
Array.of(...items)
Array.of(item_0, item_1, ···)
は、要素がitem_0
、item_1
などである配列を作成します。
Array.of()
は、Array
のサブクラスの配列リテラルとして いくつかの値を配列に変換する場合は、特に単一の値が数値である場合に配列コンストラクターが正しく機能しないため、常に配列リテラルを使用する必要があります(この癖の詳細情報)
> new Array(3, 11, 8)
[ 3, 11, 8 ]
> new Array(3)
[ , , ,]
> new Array(3.1)
RangeError: Invalid array length
では、どのように値をArray
のサブコンストラクターのインスタンスに変換する必要がありますか?これは、Array.of()
が役立つ場所です(Array
のサブコンストラクターは、of()
を含むArray
のすべてのメソッドを継承することを覚えておいてください)。
class
MyArray
extends
Array
{
···
}
console
.
log
(
MyArray
.
of
(
3
,
11
,
8
)
instanceof
MyArray
);
// true
console
.
log
(
MyArray
.
of
(
3
).
length
===
1
);
// true
Array.prototype
メソッド 配列インスタンスでいくつかの新しいメソッドが利用可能です。
次のメソッドは、配列の反復処理に役立ちます。
Array.prototype.entries()
Array.prototype.keys()
Array.prototype.values()
前述の各メソッドの結果は値のシーケンスですが、配列として返されるのではなく、イテレーターを介して1つずつ明らかにされます。例を見てみましょう。イテレーターの内容を配列に入れるために、Array.from()
を使用しています。
> Array.from(['a', 'b'].keys())
[ 0, 1 ]
> Array.from(['a', 'b'].values())
[ 'a', 'b' ]
> Array.from(['a', 'b'].entries())
[ [ 0, 'a' ],
[ 1, 'b' ] ]
また、スプレッド演算子(...
)を使用して、イテレーターを配列に変換することもできました。
> [...['a', 'b'].keys()]
[ 0, 1 ]
[index, element]
ペアの反復処理 entries()
をECMAScript 6のfor-of
ループおよびデストラクチャリングと組み合わせて、[index, element]
ペアを便利に反復処理できます。
for
(
const
[
index
,
element
]
of
[
'a'
,
'b'
].
entries
())
{
console
.
log
(
index
,
element
);
}
Array.prototype.find(predicate, thisArg?)
コールバックpredicate
がtrue
を返す最初の配列要素を返します。そのような要素がない場合は、undefined
を返します。例
> [6, -5, 8].find(x => x < 0)
-5
> [6, 5, 8].find(x => x < 0)
undefined
Array.prototype.findIndex(predicate, thisArg?)
コールバックpredicate
がtrue
を返す最初の要素のインデックスを返します。そのような要素がない場合は、-1
を返します。例
> [6, -5, 8].findIndex(x => x < 0)
1
> [6, 5, 8].findIndex(x => x < 0)
-1
コールバックpredicate
の完全な署名は次のとおりです。
predicate
(
element
,
index
,
array
)
findIndex()
によるNaN
の検索 Array.prototype.indexOf()
のよく知られた制限は、===
を介して要素を検索するため、NaN
を見つけることができないことです。
> [NaN].indexOf(NaN)
-1
findIndex()
を使用すると、Object.is()
(OOPの章で説明)を使用でき、そのような問題は発生しません。
> [NaN].findIndex(y => Object.is(NaN, y))
0
ヘルパー関数elemIs()
を作成することで、より一般的なアプローチを採用することもできます。
> function elemIs(x) { return Object.is.bind(Object, x) }
> [NaN].findIndex(elemIs(NaN))
0
Array.prototype.copyWithin()
このメソッドの署名は次のとおりです。
Array
.
prototype
.
copyWithin
(
target
:
number
,
start
:
number
,
end
=
this
.
length
)
:
This
インデックスが範囲[start
,end
)にある要素をインデックスtarget
とその後のインデックスにコピーします。2つのインデックス範囲が重なる場合、すべてのソース要素が上書きされる前にコピーされるように注意が払われます。
例
>
const
arr
=
[
0
,
1
,
2
,
3
];
>
arr
.
copyWithin
(
2
,
0
,
2
)
[
0
,
1
,
0
,
1
]
>
arr
[
0
,
1
,
0
,
1
]
Array.prototype.fill()
このメソッドの署名は次のとおりです。
Array
.
prototype
.
fill
(
value
:
any
,
start
=
0
,
end
=
this
.
length
)
:
This
配列を指定されたvalue
で埋めます。
> const arr = ['a', 'b', 'c'];
> arr.fill(7)
[ 7, 7, 7 ]
> arr
[ 7, 7, 7 ]
オプションで、埋め込みが開始および終了する場所を制限できます。
> ['a', 'b', 'c'].fill(7, 1, 2)
[ 'a', 7, 'c' ]
穴は、関連付けられた要素がない配列「内」のインデックスです。言い換えれば、配列arr
は、次の場合にインデックスi
に穴があるとされます。
i
< arr.length
!(i in arr)
例:次の配列には、インデックス1に穴があります。
> const arr = ['a',,'b']
'use strict'
> 0 in arr
true
> 1 in arr
false
> 2 in arr
true
> arr[1]
undefined
このセクションでは、穴に関する多くの例が表示されます。不明な点がある場合は、「JavaScriptの理解」のセクション「配列の穴」を参照してください。
undefined
要素のように扱う ES6で新しい配列メソッドの一般的なルールは、各穴は要素undefined
であるかのように扱われることです。例
> Array.from(['a',,'b'])
[ 'a', undefined, 'b' ]
> [,'a'].findIndex(x => x === undefined)
0
> [...[,'a'].entries()]
[ [ 0, undefined ], [ 1, 'a' ] ]
これは、人々を穴から遠ざけ、長期的に単純化することを目的としています。残念ながら、それは物事がさらに一貫性がなくなったことを意味します。
Array.prototype[Symbol.iterator]
によって作成されたイテレーターは、各穴を要素undefined
であるかのように扱います。たとえば、次のイテレーターiter
を使用します。
> var arr = [, 'a'];
> var iter = arr[Symbol.iterator]();
next()
を2回呼び出すと、インデックス0に穴があり、インデックス1に要素'a'
があります。ご覧のとおり、前者はundefined
を生成します。
> iter.next()
{ value: undefined, done: false }
> iter.next()
{ value: 'a', done: false }
とりわけ、2つの操作が反復プロトコルに基づいています。したがって、これらの操作も穴をundefined
要素として扱います。
まず、スプレッド演算子(...
)です。
> [...[, 'a']]
[ undefined, 'a' ]
次に、for-of
ループです。
for
(
const
x
of
[,
'a'
])
{
console
.
log
(
x
);
}
// Output:
// undefined
// a
配列プロトタイプメソッド(filter()
など)は、反復プロトコルを使用しないことに注意してください。
Array.from()
その引数が反復可能な場合、Array.from()
は反復処理を使用してそれを配列に変換します。次に、スプレッド演算子とまったく同じように機能します。
> Array.from([, 'a'])
[ undefined, 'a' ]
しかし、Array.from()
は配列のようなオブジェクトを配列に変換することもできます。この場合、穴はundefined
になります。
> Array.from({1: 'a', length: 2})
[ undefined, 'a' ]
2番目の引数を指定すると、Array.from()
はほとんどArray.prototype.map()
のように動作します。
ただし、Array.from()
は穴をundefined
として扱います。
> Array.from([,'a'], x => x)
[ undefined, 'a' ]
> Array.from([,'a'], (x,i) => i)
[ 0, 1 ]
Array.prototype.map()
は穴をスキップしますが、保持します。
> [,'a'].map(x => x)
[ , 'a' ]
> [,'a'].map((x,i) => i)
[ , 1 ]
Array.prototype
メソッド ECMAScript 5では、すでに動作に若干の違いがありました。例えば
forEach()
、filter()
、every()
、およびsome()
は穴を無視します。map()
は穴をスキップしますが、保持します。join()
とtoString()
は穴をundefined
要素であるかのように扱いますが、null
とundefined
の両方を空文字列として解釈します。ECMAScript 6では、新しい種類の動作が追加されました。
copyWithin()
は、穴をコピーする際に穴を作成します(つまり、必要に応じて要素を削除します)。entries()
、keys()
、values()
は、各穴を要素undefined
であるかのように扱います。find()
とfindIndex()
も同様です。fill()
は、インデックスに要素があるかどうかを気にしません。次の表は、Array.prototype
メソッドが穴をどのように処理するかを示しています。
メソッド | 穴は | |
---|---|---|
concat |
保持される | ['a',,'b'].concat(['c',,'d']) → ['a',,'b','c',,'d'] |
copyWithin ES6 |
保持される | [,'a','b',,].copyWithin(2,0) → [,'a',,'a'] |
entries ES6 |
要素 | [...[,'a'].entries()] → [[0,undefined], [1,'a']] |
every |
無視される | [,'a'].every(x => x==='a') → true |
fill ES6 |
埋められる | new Array(3).fill('a') → ['a','a','a'] |
filter |
削除される | ['a',,'b'].filter(x => true) → ['a','b'] |
find ES6 |
要素 | [,'a'].find(x => true) → undefined |
findIndex ES6 |
要素 | [,'a'].findIndex(x => true) → 0 |
forEach |
無視される | [,'a'].forEach((x,i) => log(i)); → 1 |
indexOf |
無視される | [,'a'].indexOf(undefined) → -1 |
join |
要素 | [,'a',undefined,null].join('#') → '#a##' |
keys ES6 |
要素 | [...[,'a'].keys()] → [0,1] |
lastIndexOf |
無視される | [,'a'].lastIndexOf(undefined) → -1 |
map |
保持される | [,'a'].map(x => 1) → [,1] |
pop |
要素 | ['a',,].pop() → undefined |
push |
保持される | new Array(1).push('a') → 2 |
reduce |
無視される | ['#',,undefined].reduce((x,y)=>x+y) → '#undefined' |
reduceRight |
無視される | ['#',,undefined].reduceRight((x,y)=>x+y) → 'undefined#' |
reverse |
保持される | ['a',,'b'].reverse() → ['b',,'a'] |
shift |
要素 | [,'a'].shift() → undefined |
slice |
保持される | [,'a'].slice(0,1) → [,] |
some |
無視される | [,'a'].some(x => x !== 'a') → false |
sort |
保持される | [,undefined,'a'].sort() → ['a',undefined,,] |
splice |
保持される | ['a',,].splice(1,1) → [,] |
toString |
要素 | [,'a',undefined,null].toString() → ',a,,' |
unshift |
保持される | [,'a'].unshift('b') → 3 |
values ES6 |
要素 | [...[,'a'].values()] → [undefined,'a'] |
注
['a',,].length → 2
const log = console.log.bind(console);
新しいES6操作で穴がundefined
要素として扱われることは、値で埋められた配列の作成に役立ちます。
Array.prototype.fill()
は、すべての配列要素(穴を含む)を固定値で置き換えます。
> new Array(3).fill(7)
[ 7, 7, 7 ]
new Array(3)
は3つの穴を持つ配列を作成し、fill()
は各穴を値7
で置き換えます。
Array.prototype.keys()
は、配列に穴しかない場合でもキーを報告します。これはイテラブルを返し、スプレッド演算子を使って配列に変換できます。
> [...new Array(3).keys()]
[ 0, 1, 2 ]
Array.from()
の2番目のパラメータのマップ関数は、穴を通知されます。したがって、Array.from()
を使用して、より洗練された埋め込みを行うことができます。
> Array.from(new Array(5), (x,i) => i*2)
[ 0, 2, 4, 6, 8 ]
undefined
で埋める undefined
で埋められた配列が必要な場合は、イテレーション(スプレッド演算子によってトリガーされる)が穴をundefined
に変換するという事実を利用できます。
> [...new Array(3)]
[ undefined, undefined, undefined ]
ES5メソッドfilter()
を使用すると、穴を削除できます。
> ['a',,'c'].filter(() => true)
[ 'a', 'c' ]
ES6イテレーション(スプレッド演算子によってトリガーされる)を使用すると、穴をundefined
要素に変換できます。
> [...['a',,'c']]
[ 'a', undefined, 'c' ]
concat()
でスプレッドされるオブジェクトを設定する (Symbol.isConcatSpreadable
) キーがよく知られたシンボルSymbol.isConcatSpreadable
で、値がブール値である(独自または継承された)プロパティを追加することで、Array.prototype.concat()
がオブジェクトをどのように扱うかを設定できます。
デフォルトでは、Array.prototype.concat()
は配列を結果にスプレッドします。つまり、インデックス付き要素が結果の要素になります。
const
arr1
=
[
'c'
,
'd'
];
[
'a'
,
'b'
].
concat
(
arr1
,
'e'
);
// ['a', 'b', 'c', 'd', 'e']
Symbol.isConcatSpreadable
を使用すると、デフォルトをオーバーライドし、配列のスプレッドを回避できます。
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']
Symbol.isConcatSpreadable
を使用して、スプレッドを強制できます。
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']
concat()
は、パラメータが配列かどうかをどのように判断するのでしょうか? これは、Array.isArray()
と同じアルゴリズムを使用します。Array.prototype
がプロトタイプチェーンにあるかどうかは、そのアルゴリズムにとっては何の違いもありません。これは重要です。なぜなら、ES5以前では、Array
をサブクラス化するためにハックが使用され、それらは引き続き機能する必要があるからです (この本の__proto__
に関するセクションを参照)。
> const arr = [];
> Array.isArray(arr)
true
> Object.setPrototypeOf(arr, null);
> Array.isArray(arr)
true
Symbol.isConcatSpreadable
ES6標準ライブラリには、キーがSymbol.isConcatSpreadable
であるプロパティを持つオブジェクトはありません。したがって、このメカニズムは、ブラウザAPIとユーザーコードのみを対象としています。
結果
Array
のサブクラスは、デフォルトでスプレッドされます(そのインスタンスが配列オブジェクトであるため)。Array
のサブクラスは、キーがSymbol.isConcatSpreadable
であるプロパティをfalse
に設定することで、そのインスタンスがスプレッドされるのを防ぐことができます。そのプロパティは、プロトタイププロパティまたはインスタンスプロパティのいずれかになります。[Symbol.isConcatSpreadable]
がtrue
の場合、concat()
によってスプレッドされます。これにより、たとえば、一部の配列のようなDOMコレクションのスプレッドを有効にすることができます。concat()
メソッドもありません。配列の場合、ES6はES5と同じルールを持っています。
l
は、0 ≤ l
≤ 232−1の範囲です。i
は、0 ≤ i
< 232−1の範囲です。文字列とTyped Arraysは、より大きなインデックス範囲を持っています。0 ≤ i
< 253−1。その範囲の上限は、253−1がJavaScriptの浮動小数点数が安全に表現できる最大の整数であるためです。詳細については、「安全な整数」を参照してください。
通常の配列のインデックス範囲が小さい唯一の理由は、下位互換性です。