Array
).length
for-of
ループと配列 [ES6]for-of
:要素の反復処理for-of
:インデックスの反復処理for-of
:[インデックス、要素]ペアの反復処理...
)によるイテラブルの配列への変換Array.from()
によるイテラブルと配列様オブジェクトの配列への変換.find()
、.map()
、.filter()
など).find()
、.findIndex()
.map()
:要素の値を変更しながらコピーする.flatMap()
:0個以上の値へのマッピング.filter()
:一部の要素だけを保持する.reduce()
:配列からの値の導出(上級).sort()
:配列のソートArray
new Array()
Array
の静的メソッドArray.prototype
のメソッドJavaScriptの配列は非常に柔軟なデータ構造であり、リスト、スタック、キュー、タプル(例:ペア)などとして使用されます。
配列関連操作の中には、配列を破壊的に変更するものと、元のコンテンツのコピーに変更を適用して新しい配列を非破壊的に生成するものがあります。
配列の作成、要素の読み取りと書き込み
// Creating an Array
const arr = ['a', 'b', 'c']; // Array literal
.deepEqual(
assert,
arr// Array literal
[ 'a',
'b',
'c', // trailing commas are ignored
];
)
// Reading elements
.equal(
assert0], 'a' // negative indices don’t work
arr[;
).equal(
assert.at(-1), 'c' // negative indices work
arr;
)
// Writing an element
0] = 'x';
arr[.deepEqual(
assert, ['x', 'b', 'c']
arr; )
配列の長さ
const arr = ['a', 'b', 'c'];
.equal(
assert.length, 3 // number of elements
arr;
).length = 1; // removing elements
arr.deepEqual(
assert, ['a']
arr;
).length] = 'b'; // adding an element
arr[arr.deepEqual(
assert, ['a', 'b']
arr; )
.push()
による破壊的な要素の追加
const arr = ['a', 'b'];
.push('c'); // adding an element
arr.deepEqual(
assert, ['a', 'b', 'c']
arr;
)
// Pushing Arrays (used as arguments via spreading (...)):
.push(...['d', 'e']);
arr.deepEqual(
assert, ['a', 'b', 'c', 'd', 'e']
arr; )
スプレッド構文(...
)による非破壊的な要素の追加
const arr1 = ['a', 'b'];
const arr2 = ['c'];
.deepEqual(
assert...arr1, ...arr2, 'd', 'e'],
['a', 'b', 'c', 'd', 'e']
[; )
配列のクリア(すべての要素の削除)
// Destructive – affects everyone referring to the Array:
const arr1 = ['a', 'b', 'c'];
.length = 0;
arr1.deepEqual(
assert, []
arr1;
)
// Non-destructive – does not affect others referring to the Array:
let arr2 = ['a', 'b', 'c'];
= [];
arr2 .deepEqual(
assert, []
arr2; )
要素のループ処理
const arr = ['a', 'b', 'c'];
for (const value of arr) {
console.log(value);
}
// Output:
// 'a'
// 'b'
// 'c'
インデックスと値のペアのループ処理
const arr = ['a', 'b', 'c'];
for (const [index, value] of arr.entries()) {
console.log(index, value);
}
// Output:
// 0, 'a'
// 1, 'b'
// 2, 'c'
配列リテラルを使用できない場合(例:事前に長さがわからない場合、または大きすぎる場合)の配列の作成と初期化
const four = 4;
// Empty Array that we’ll fill later
.deepEqual(
assertnew Array(four),
, , , ,] // four holes; last comma is ignored
[ ;
)
// An Array filled with a primitive value
.deepEqual(
assertnew Array(four).fill(0),
0, 0, 0, 0]
[;
)
// An Array filled with objects
// Why not .fill()? We’d get single object, shared multiple times.
.deepEqual(
assertArray.from({length: four}, () => ({})),
, {}, {}, {}]
[{};
)
// A range of integers
.deepEqual(
assertArray.from({length: four}, (_, i) => i),
0, 1, 2, 3]
[; )
この節では、Array APIの概要を簡単に説明します。この章の最後には、より包括的なクイックリファレンスがあります。
既存の配列から新しい配列を導出する
> ['■','●','▲'].slice(1, 3)['●','▲']
> ['■','●','■'].filter(x => x==='■') ['■','■']
> ['▲','●'].map(x => x+x)['▲▲','●●']
> ['▲','●'].flatMap(x => [x,x])['▲','▲','●','●']
指定されたインデックスにある配列要素を削除する
// .filter(): remove non-destructively
const arr1 = ['■','●','▲'];
.deepEqual(
assert.filter((_, index) => index !== 1),
arr1'■','▲']
[;
).deepEqual(
assert, ['■','●','▲'] // unchanged
arr1;
)
// .splice(): remove destructively
const arr2 = ['■','●','▲'];
.splice(1, 1); // start at 1, delete 1 element
arr2.deepEqual(
assert, ['■','▲'] // changed
arr2; )
配列のサマリーを計算する
> ['■','●','▲'].some(x => x==='●')true
> ['■','●','▲'].every(x => x==='●')false
> ['■','●','▲'].join('-')'■-●-▲'
> ['■','▲'].reduce((result,x) => result+x, '●')'●■▲'
> ['■','▲'].reduceRight((result,x) => result+x, '●')'●▲■'
反転と初期化
// .reverse() changes and returns `arr`
const arr = ['■','●','▲'];
.deepEqual(
assert.reverse(), arr
arr;
)// `arr` was changed:
.deepEqual(
assert, ['▲','●','■']
arr;
)
// .fill() works the same way:
.deepEqual(
assert'■','●','▲'].fill('●'),
['●','●','●']
[; )
.sort()
も配列を変更して返します
// By default, string representations of the Array elements
// are sorted lexicographically:
.deepEqual(
assert200, 3, 10].sort(),
[10, 200, 3]
[;
)
// Sorting can be customized via a callback:
.deepEqual(
assert200, 3, 10].sort((a,b) => a - b), // sort numerically
[3, 10, 200 ]
[ ; )
配列要素の検索
> ['■','●','■'].includes('■')true
> ['■','●','■'].indexOf('■')0
> ['■','●','■'].lastIndexOf('■')2
> ['■','●','■'].find(x => x==='■')'■'
> ['■','●','■'].findIndex(x => x==='■')0
先頭または末尾への要素の追加または削除
// Adding and removing at the start
const arr1 = ['■','●'];
.unshift('▲');
arr1.deepEqual(
assert, ['▲','■','●']
arr1;
).shift();
arr1.deepEqual(
assert, ['■','●']
arr1;
)
// Adding and removing at the end
const arr2 = ['■','●'];
.push('▲');
arr2.deepEqual(
assert, ['■','●','▲']
arr2;
).pop();
arr2.deepEqual(
assert, ['■','●']
arr2; )
JavaScriptでは、配列を2つの方法で使用できます。
実際には、これらの2つの方法はよく混在して使用されます。
特に、シーケンス配列は非常に柔軟なため、(従来の)配列、スタック、キューとして使用できます。その方法は後で説明します。
配列を作成する最良の方法は、配列リテラルを使用することです。
const arr = ['a', 'b', 'c'];
配列リテラルは角括弧[]
で始まり、終わります。3つの要素:'a'
、'b'
、'c'
を持つ配列を作成します。
末尾のカンマは配列リテラルでは許可され、無視されます。
const arr = [
'a',
'b',
'c',
; ]
配列要素を読み取るには、角括弧の中にインデックスを入れます(インデックスは0から始まります)。
const arr = ['a', 'b', 'c'];
.equal(arr[0], 'a'); assert
配列要素を変更するには、インデックス付きの配列に代入します。
const arr = ['a', 'b', 'c'];
0] = 'x';
arr[.deepEqual(arr, ['x', 'b', 'c']); assert
配列インデックスの範囲は32ビット(最大長を除く)です:[0, 232−1)
.length
すべての配列には.length
プロパティがあり、これを使用して配列の要素数を取得および変更(!)することができます。
配列の長さは常に最大のインデックスに1を加えた値になります。
> const arr = ['a', 'b'];
> arr.length2
長さのインデックスの配列に書き込むと、要素が追加されます。
> arr[arr.length] = 'c';
> arr[ 'a', 'b', 'c' ]
> arr.length3
要素を(破壊的に)追加する別の方法は、.push()
配列メソッドを使用することです。
> arr.push('d');
> arr[ 'a', 'b', 'c', 'd' ]
.length
を設定すると、要素を削除して配列が切り詰められます。
> arr.length = 1;
> arr[ 'a' ]
練習問題:
.push()
を使用した空行の削除
exercises/arrays/remove_empty_lines_push_test.mjs
いくつかの配列メソッドは負のインデックスをサポートしています。インデックスが負の場合、配列の長さに加算されて使用可能なインデックスが生成されます。したがって、次の2つの.slice()
の呼び出しは同等です。どちらも最後の要素から始まるarr
のコピーを作成します。
> const arr = ['a', 'b', 'c'];
> arr.slice(-1)[ 'c' ]
> arr.slice(arr.length - 1)[ 'c' ]
.at()
:単一要素の読み取り(負のインデックスをサポート)[ES2022]配列メソッド.at()
は、指定されたインデックスの要素を返します。正のインデックスと負のインデックスの両方をサポートします(-1
は最後の要素、-2
は最後から2番目の要素などを指します)。
> ['a', 'b', 'c'].at(0)'a'
> ['a', 'b', 'c'].at(-1)'c'
一方、角括弧演算子[]
は負のインデックスをサポートしません(既存のコードを壊すため変更できません)。それらは非要素プロパティのキーとして解釈されます。
const arr = ['a', 'b', 'c'];
-1] = 'non-element property';
arr[// The Array elements didn’t change:
.deepEqual(
assertArray.from(arr), // copy just the Array elements
'a', 'b', 'c']
[;
)
.equal(
assert-1], 'non-element property'
arr[; )
配列をクリア(空にする)するには、.length
を0に設定します。
const arr = ['a', 'b', 'c'];
.length = 0;
arr.deepEqual(arr, []); assert
または、空の新しい配列を配列を格納している変数に代入します。
let arr = ['a', 'b', 'c'];
= [];
arr .deepEqual(arr, []); assert
後者の方法は、同じ配列を指している他の場所に影響を与えないという利点があります。ただし、共有配列を全員のためにリセットする必要がある場合は、前者の方法を使用する必要があります。
配列リテラル内では、スプレッド要素は3つのドット(...
)とそれに続く式で構成されます。式が評価され、反復処理されます。反復処理された各値は、追加の配列要素になります。例:
> const iterable = ['b', 'c'];
> ['a', ...iterable, 'd'][ 'a', 'b', 'c', 'd' ]
つまり、スプレッド構文を使用して配列のコピーを作成し、イテラブルを配列に変換できます。
const original = ['a', 'b', 'c'];
const copy = [...original];
const iterable = original.keys();
.deepEqual(
assert...iterable], [0, 1, 2]
[; )
ただし、上記の2つのユースケースについては、Array.from()
の方が自己記述的で、個人的には好んでいます。
const copy2 = Array.from(original);
.deepEqual(
assertArray.from(original.keys()), [0, 1, 2]
; )
スプレッド構文は、配列(およびその他のイテラブル)を配列に連結する場合にも便利です。
const arr1 = ['a', 'b'];
const arr2 = ['c', 'd'];
const concatenated = [...arr1, ...arr2, 'e'];
.deepEqual(
assert,
concatenated'a', 'b', 'c', 'd', 'e']); [
スプレッド構文は反復処理を使用するため、値がイテラブルである場合にのみ機能します。
> [...'abc'] // strings are iterable[ 'a', 'b', 'c' ]
> [...123]TypeError: 123 is not iterable
> [...undefined]TypeError: undefined is not iterable
スプレッド構文と
Array.from()
は浅いコピーを作成します
スプレッド構文またはArray.from()
を使用して配列をコピーすると、浅いコピーが作成されます。新しい配列に新しいエントリが作成されますが、値は元の配列と共有されます。浅いコピーの結果については、§28.4「オブジェクトリテラルへのスプレッド構文(...
)[ES2018]」で説明しています。
.keys()
メソッドは配列のインデックスを列挙します。
const arr = ['a', 'b'];
.deepEqual(
assertArray.from(arr.keys()), // (A)
0, 1]); [
.keys()
はイテラブルを返します。A行では、そのイテラブルを配列に変換しています。
配列インデックスの列挙は、プロパティの列挙とは異なります。前者は数値を生成し、後者は数値の文字列表現(インデックス以外のプロパティキーに加えて)を生成します。
const arr = ['a', 'b'];
.prop = true;
arr
.deepEqual(
assertObject.keys(arr),
'0', '1', 'prop']); [
.entries()
メソッドは、配列の内容を[インデックス、要素]ペアとして列挙します。
const arr = ['a', 'b'];
.deepEqual(
assertArray.from(arr.entries()),
0, 'a'], [1, 'b']]); [[
値が配列かどうかを確認する方法は2つあります。
> [] instanceof Arraytrue
> Array.isArray([])true
instanceof
は通常問題ありません。値が別のレルムから来る可能性がある場合は、Array.isArray()
が必要です。簡単に言うと、レルムはJavaScriptのグローバルスコープのインスタンスです。一部のレルムは互いに分離されています(例:ブラウザのWeb Worker)。しかし、データの移動ができるレルムもあります。例えば、ブラウザの同一オリジンのiframeなどです。x instanceof Array
はx
のプロトタイプチェーンをチェックするため、x
が別のレルムの配列である場合はfalse
を返します。
typeof
は配列をオブジェクトとして分類します。
> typeof []'object'
for-of
ループと配列 [ES6]本書では既にfor-of
ループについて触れています。このセクションでは、配列に対する使用方法を簡単に要約します。
for-of
:要素の反復処理以下のfor-of
ループは、配列の要素を反復処理します。
for (const element of ['a', 'b']) {
console.log(element);
}// Output:
// 'a'
// 'b'
for-of
:インデックスの反復処理このfor-of
ループは、配列のインデックスを反復処理します。
for (const element of ['a', 'b'].keys()) {
console.log(element);
}// Output:
// 0
// 1
for-of
:[インデックス、要素]ペアの反復処理以下のfor-of
ループは、[インデックス、要素]ペアを反復処理します。後述するデストラクチャリングにより、for-of
の先頭でindex
とelement
を設定するための便利な構文が得られます。
for (const [index, element] of ['a', 'b'].entries()) {
console.log(index, element);
}// Output:
// 0, 'a'
// 1, 'b'
配列で動作する操作の中には、最小限の要件しか必要としないものがあります。値は配列のようなオブジェクトである必要があります。配列のような値とは、以下のプロパティを持つオブジェクトです。
.length
:配列のようなオブジェクトの長さを保持します。[0]
:インデックス0の要素を保持します(以下同様)。プロパティ名として数値を使用する場合、常に文字列に変換されます。したがって、[0]
はキーが'0'
であるプロパティの値を取得します。例えば、Array.from()
は配列のようなオブジェクトを受け入れ、配列に変換します。
// If we omit .length, it is interpreted as 0
.deepEqual(
assertArray.from({}),
;
[])
.deepEqual(
assertArray.from({length:2, 0:'a', 1:'b'}),
'a', 'b' ]); [
配列のようなオブジェクトのTypeScriptインターフェースは次のとおりです。
interface ArrayLike<T> {
: number;
length: number]: T;
[n }
現代のJavaScriptでは、配列のようなオブジェクトは比較的まれです
配列のようなオブジェクトはES6以前は一般的でしたが、今ではあまり見かけません。
反復可能オブジェクトと配列のような値を配列に変換する一般的な方法は2つあります。
Array.from()
後者の方が、より分かりやすいので好みです。
...
)による反復可能オブジェクトの配列への変換配列リテラル内では、...
によるスプレッド構文は、任意の反復可能オブジェクトを配列要素のシーケンスに変換します。例えば、
// Get an Array-like collection from a web browser’s DOM
const domCollection = document.querySelectorAll('a');
// Alas, the collection is missing many Array methods
.equal('map' in domCollection, false);
assert
// Solution: convert it to an Array
const arr = [...domCollection];
.deepEqual(
assert.map(x => x.href),
arr'https://2ality.com', 'https://exploringjs.dokyumento.jp']); [
DOMコレクションは反復可能であるため、変換が機能します。
Array.from()
による反復可能オブジェクトと配列のようなオブジェクトの配列への変換Array.from()
は2つのモードで使用できます。
Array.from()
のモード1:変換最初のモードは、次の型シグネチャを持ちます。
.from<T>(iterable: Iterable<T> | ArrayLike<T>): T[]
Iterable
インターフェースは同期反復処理に関する章で、ArrayLike
インターフェースは本章の以前のセクションで説明されています。
パラメータを1つだけ指定した場合、Array.from()
は反復可能オブジェクトまたは配列のようなオブジェクトを配列に変換します。
> Array.from(new Set(['a', 'b']))[ 'a', 'b' ]
> Array.from({length: 2, 0:'a', 1:'b'})[ 'a', 'b' ]
Array.from()
のモード2:変換とマッピングArray.from()
の2番目のモードには、2つのパラメータが含まれます。
.from<T, U>(
: Iterable<T> | ArrayLike<T>,
iterable: (v: T, i: number) => U,
mapFunc?: any)
thisArg: U[]
このモードでは、Array.from()
はいくつかの処理を行います。
iterable
を反復処理します。mapFunc
を呼び出します。オプションのパラメータthisArg
は、mapFunc
のthis
を指定します。mapFunc
を適用します。つまり、型T
の要素を持つ反復可能オブジェクトから、型U
の要素を持つ配列に変換されます。
これは一例です。
> Array.from(new Set(['a', 'b']), x => x + x)[ 'aa', 'bb' ]
配列を作成する最良の方法は、配列リテラルを使用することです。しかし、常にそれが可能なわけではありません。配列が大きすぎる場合、開発中に長さが分からない場合、または長さを柔軟に保ちたい場合があります。そのような場合、配列の作成と場合によっては埋め込みに、以下の手法をお勧めします。
> new Array(3)[ , , ,]
結果は3つの穴(空のスロット)を持っています。配列リテラルの最後のコンマは常に無視されます。
> new Array(3).fill(0)[0, 0, 0]
注意:オブジェクトで.fill()
を使用する場合、各配列要素は(共有して)このオブジェクトを参照します。
const arr = new Array(3).fill({});
0].prop = true;
arr[.deepEqual(
assert, [
arrprop: true},
{prop: true},
{prop: true},
{; ])
次の小節では、この問題の解決策を説明します。
> new Array(3).fill(0)[0, 0, 0]
大きなサイズの場合、一時的な配列はかなりのメモリを消費する可能性があります。次のアプローチにはこの欠点はありませんが、自己説明的な記述が少ないです。
> Array.from({length: 3}, () => ({}))[{}, {}, {}]
一時的な配列の代わりに、一時的な配列のようなオブジェクトを使用しています。
function createRange(start, end) {
return Array.from({length: end-start}, (_, i) => i+start);
}.deepEqual(
assertcreateRange(2, 5),
2, 3, 4]); [
0から始まる整数の範囲を作成するための、少し技巧的な代替手法を次に示します。
/** Returns an iterable */
function createRange(end) {
return new Array(end).keys();
}.deepEqual(
assertArray.from(createRange(4)),
0, 1, 2, 3]); [
これは、.keys()
が穴をundefined
要素として扱い、そのインデックスをリストアップするため機能します。
整数または浮動小数点数からなる配列を扱う場合、この目的のために作成された型付き配列を検討する必要があります。
JavaScriptには真の多次元配列がありません。要素が配列である配列に頼る必要があります。
function initMultiArray(...dimensions) {
function initMultiArrayRec(dimIndex) {
if (dimIndex >= dimensions.length) {
return 0;
else {
} const dim = dimensions[dimIndex];
const arr = [];
for (let i=0; i<dim; i++) {
.push(initMultiArrayRec(dimIndex+1));
arr
}return arr;
}
}return initMultiArrayRec(0);
}
const arr = initMultiArray(4, 3, 2);
3][2][1] = 'X'; // last in each dimension
arr[.deepEqual(arr, [
assert0, 0 ], [ 0, 0 ], [ 0, 0 ] ],
[ [ 0, 0 ], [ 0, 0 ], [ 0, 0 ] ],
[ [ 0, 0 ], [ 0, 0 ], [ 0, 0 ] ],
[ [ 0, 0 ], [ 0, 0 ], [ 0, 'X' ] ],
[ [ ; ])
このセクションでは、配列の操作で頻繁には遭遇しない現象を見ていきます。
配列要素は数値でアクセスするため特殊だと思うかもしれません。しかし、そのために行う角括弧演算子[]
は、プロパティへのアクセスにも使用される同じ演算子です。これはシンボル以外の任意の値を文字列に変換します。したがって、配列要素は(ほぼ)通常のプロパティ(A行)であり、インデックスとして数値または文字列を使用しても問題ありません(B行とC行)。
const arr = ['a', 'b'];
.prop = 123;
arr.deepEqual(
assertObject.keys(arr),
'0', '1', 'prop']); // (A)
[
.equal(arr[0], 'a'); // (B)
assert.equal(arr['0'], 'a'); // (C) assert
さらに混乱を招くことに、これは言語仕様でのみ定義されている方法です(JavaScriptの理論と言えるでしょう)。ほとんどのJavaScriptエンジンは内部で最適化を行い、実際に整数を用いて配列要素にアクセスしています(JavaScriptの実践と言えるでしょう)。
配列要素に使用されるプロパティキー(文字列!)はインデックスと呼ばれます。文字列str
がインデックスであるとは、それを32ビット符号なし整数に変換して元に戻した結果が元の値と同じであることを意味します。数式で書くと
ToString(ToUint32(str)) === str
プロパティキーをリストアップする場合、インデックスは特別に扱われます。常に最初に表示され、数値のようにソートされます('2'
は'10'
の前に来ます)。
const arr = [];
.prop = true;
arr1] = 'b';
arr[0] = 'a';
arr[
.deepEqual(
assertObject.keys(arr),
'0', '1', 'prop']); [
.length
、.entries()
、.keys()
は配列インデックスを数値として扱い、インデックス以外のプロパティは無視することに注意してください。
.equal(arr.length, 2);
assert.deepEqual(
assertArray.from(arr.keys()), [0, 1]);
.deepEqual(
assertArray.from(arr.entries()), [[0, 'a'], [1, 'b']]);
.keys()
と.entries()
によって返される反復可能オブジェクトを配列に変換するために、Array.from()
を使用しました。
JavaScriptでは2種類の配列を区別します。
arr
が密集型であるとは、0 ≤ i
< arr.length
であるすべてのインデックスi
が存在することを意味します。つまり、インデックスは連続した範囲を形成します。配列は実際にはインデックスから値への辞書であるため、JavaScriptでは疎型になる可能性があります。
推奨事項:穴を避ける
これまで、密集型配列しか見ていませんが、穴を避けることをお勧めします。穴はコードを複雑にし、配列メソッドによって一貫して処理されません。さらに、JavaScriptエンジンは密集型配列を最適化するため、高速になります。
要素を代入するときにインデックスをスキップすることで、穴を作成できます。
const arr = [];
0] = 'a';
arr[2] = 'c';
arr[
.deepEqual(Object.keys(arr), ['0', '2']); // (A)
assert
.equal(0 in arr, true); // element
assert.equal(1 in arr, false); // hole assert
A行では、arr.keys()
は穴をundefined
要素として扱い、それらを表示しないため、Object.keys()
を使用しています。
穴を作成するもう1つの方法は、配列リテラルで要素をスキップすることです。
const arr = ['a', , 'c'];
.deepEqual(Object.keys(arr), ['0', '2']); assert
配列要素を削除することもできます。
const arr = ['a', 'b', 'c'];
.deepEqual(Object.keys(arr), ['0', '1', '2']);
assertdelete arr[1];
.deepEqual(Object.keys(arr), ['0', '2']); assert
残念ながら、配列操作が穴を処理する方法はたくさんあります。
いくつかの配列操作は穴を削除します。
> ['a',,'b'].filter(x => true)[ 'a', 'b' ]
いくつかの配列操作は穴を無視します。
> ['a', ,'a'].every(x => x === 'a')true
いくつかの配列操作は穴を無視しますが、保持します。
> ['a',,'b'].map(x => 'c')[ 'c', , 'c' ]
いくつかの配列操作は穴をundefined
要素として扱います。
> Array.from(['a',,'b'], x => x)[ 'a', undefined, 'b' ]
> Array.from(['a',,'b'].entries())[[0, 'a'], [1, undefined], [2, 'b']]
Object.keys()
は.keys()
とは異なる動作をします(文字列と数値、穴にはキーがありません)。
> Array.from(['a',,'b'].keys())[ 0, 1, 2 ]
> Object.keys(['a',,'b'])[ '0', '2' ]
ここで覚えておくべきルールはありません。配列操作が穴をどのように処理するかが問題になる場合は、コンソールで迅速にテストするのが最善の方法です。
JavaScriptのArray
は非常に柔軟で、配列、スタック、キューの組み合わせのようです。このセクションでは、配列要素の追加と削除の方法を調べます。ほとんどの操作は、破壊的(配列の変更)と非破壊的(変更されたコピーの作成)の両方で実行できます。
以下のコードでは、単一の要素をarr1
に、配列をarr2
に破壊的に追加しています。
const arr1 = ['a', 'b'];
.unshift('x', 'y'); // prepend single elements
arr1.deepEqual(arr1, ['x', 'y', 'a', 'b']);
assert
const arr2 = ['a', 'b'];
.unshift(...['x', 'y']); // prepend Array
arr2.deepEqual(arr2, ['x', 'y', 'a', 'b']); assert
スプレッド構文を使用すると、配列をarr2
にunshiftできます。
非破壊的な先頭への追加は、スプレッド要素を使用して行われます。
const arr1 = ['a', 'b'];
.deepEqual(
assert'x', 'y', ...arr1], // prepend single elements
['x', 'y', 'a', 'b']);
[.deepEqual(arr1, ['a', 'b']); // unchanged!
assert
const arr2 = ['a', 'b'];
.deepEqual(
assert...['x', 'y'], ...arr2], // prepend Array
['x', 'y', 'a', 'b']);
[.deepEqual(arr2, ['a', 'b']); // unchanged! assert
以下のコードでは、単一の要素をarr1
に、配列をarr2
に破壊的に追加しています。
const arr1 = ['a', 'b'];
.push('x', 'y'); // append single elements
arr1.deepEqual(arr1, ['a', 'b', 'x', 'y']);
assert
const arr2 = ['a', 'b'];
.push(...['x', 'y']); // (A) append Array
arr2.deepEqual(arr2, ['a', 'b', 'x', 'y']); assert
スプレッド構文(...
)を使用すると、配列をarr2
にpushできます(A行)。
非破壊的な末尾への追加は、スプレッド要素を使用して行われます。
const arr1 = ['a', 'b'];
.deepEqual(
assert...arr1, 'x', 'y'], // append single elements
['a', 'b', 'x', 'y']);
[.deepEqual(arr1, ['a', 'b']); // unchanged!
assert
const arr2 = ['a', 'b'];
.deepEqual(
assert...arr2, ...['x', 'y']], // append Array
['a', 'b', 'x', 'y']);
[.deepEqual(arr2, ['a', 'b']); // unchanged! assert
配列要素を削除する3つの破壊的な方法を次に示します。
// Destructively remove first element:
const arr1 = ['a', 'b', 'c'];
.equal(arr1.shift(), 'a');
assert.deepEqual(arr1, ['b', 'c']);
assert
// Destructively remove last element:
const arr2 = ['a', 'b', 'c'];
.equal(arr2.pop(), 'c');
assert.deepEqual(arr2, ['a', 'b']);
assert
// Remove one or more elements anywhere:
const arr3 = ['a', 'b', 'c', 'd'];
.deepEqual(arr3.splice(1, 2), ['b', 'c']);
assert.deepEqual(arr3, ['a', 'd']); assert
.splice()
については、本章の最後にあるクイックリファレンスで詳しく説明します。
rest要素によるデストラクチャリングにより、配列の先頭から要素を非破壊的に削除できます(デストラクチャリングについては後述します)。
const arr1 = ['a', 'b', 'c'];
// Ignore first element, extract remaining elements
const [, ...arr2] = arr1;
.deepEqual(arr2, ['b', 'c']);
assert.deepEqual(arr1, ['a', 'b', 'c']); // unchanged! assert
しかし、rest要素は配列の最後に来る必要があります。したがって、接尾辞を抽出するためだけに使用できます。
演習:配列を使用したキューの実装
exercises/arrays/queue_via_array_test.mjs
.find()
、.map()
、.filter()
など)このセクションでは、配列の反復処理と変換を行う配列メソッドについて見ていきます。
すべての反復処理と変換メソッドはコールバックを使用します。前者はすべての反復値をコールバックに供給し、後者はコールバックに配列の変換方法を尋ねます。
これらのコールバックは、次の型シグネチャを持ちます。
: (value: T, index: number, array: Array<T>) => boolean callback
つまり、コールバックは3つのパラメータを取得します(いずれかのパラメータを無視しても構いません)。
value
は最も重要なパラメータです。このパラメータは、現在処理されている反復値を保持します。index
は、コールバックに反復値のインデックスを知らせることができます。array
は現在の配列(メソッド呼び出しの受信者)を指します。いくつかのアルゴリズムは、全体配列を参照する必要があります(例えば、答えを検索するため)。このパラメータを使用すると、そのようなアルゴリズムに対して再利用可能なコールバックを作成できます。コールバックが返す内容はそのメソッドによって異なります。可能性としては以下があります。
.map()
は、コールバック関数が返す値で結果を埋めます。
> ['a', 'b', 'c'].map(x => x + x)[ 'aa', 'bb', 'cc' ]
.find()
は、コールバック関数が true
を返す最初の配列要素を返します。
> ['a', 'bb', 'ccc'].find(str => str.length >= 2)'bb'
これらのメソッドの詳細は、後で詳しく説明します。
.find()
、.findIndex()
.find()
は、コールバック関数が真偽値(truthy value)を返す最初の要素を返し、何も見つからない場合は undefined
を返します。
> [6, -5, 8].find(x => x < 0)-5
> [6, 5, 8].find(x => x < 0)undefined
.findIndex()
は、コールバック関数が真偽値を返す最初の要素のインデックスを返し、何も見つからない場合は -1
を返します。
> [6, -5, 8].findIndex(x => x < 0)1
> [6, 5, 8].findIndex(x => x < 0)-1
.findIndex()
は、次のように実装できます。
function findIndex(arr, callback) {
for (const [i, x] of arr.entries()) {
if (callback(x, i, arr)) {
return i;
}
}return -1;
}
.map()
: 要素に新しい値を与えながらコピーする.map()
は、レシーバ(元の配列)の修正済みコピーを返します。コピーの要素は、map
のコールバック関数をレシーバの要素に適用した結果です。
これらすべては、例を通して理解するのが容易です。
> [1, 2, 3].map(x => x * 3)[ 3, 6, 9 ]
> ['how', 'are', 'you'].map(str => str.toUpperCase())[ 'HOW', 'ARE', 'YOU' ]
> [true, true, true].map((_x, index) => index)[ 0, 1, 2 ]
.map()
は、次のように実装できます。
function map(arr, mapFunc) {
const result = [];
for (const [i, x] of arr.entries()) {
.push(mapFunc(x, i, arr));
result
}return result;
}
練習問題:
.map()
を使用した行番号付け
exercises/arrays/number_lines_test.mjs
.flatMap()
: 0個以上の値へのマッピングArray<T>.prototype.flatMap()
の型シグネチャは次のとおりです。
.flatMap<U>(
: (value: T, index: number, array: T[]) => U|Array<U>,
callback?: any
thisValue: U[] )
.map()
と .flatMap()
はどちらも、入力配列を出力配列に変換する方法を制御する関数 callback
をパラメータとして受け取ります。
.map()
では、各入力配列要素は正確に1つの出力要素に変換されます。つまり、callback
は単一の値を返します。.flatMap()
では、各入力配列要素は0個以上の出力要素に変換されます。つまり、callback
は値の配列を返します(配列以外の値を返すこともできますが、まれです)。これが .flatMap()
の動作です。
> ['a', 'b', 'c'].flatMap(x => [x,x])[ 'a', 'a', 'b', 'b', 'c', 'c' ]
> ['a', 'b', 'c'].flatMap(x => [x])[ 'a', 'b', 'c' ]
> ['a', 'b', 'c'].flatMap(x => [])[]
このメソッドの実装方法を検討する前に、ユースケースを検討します。
配列メソッド .map()
の結果は、常に呼び出された配列と同じ長さになります。つまり、そのコールバック関数は、関心のない配列要素をスキップできません。.flatMap()
がこれを行う機能は、次の例で役立ちます。
次の関数 processArray()
を使用して配列を作成し、その後 .flatMap()
を使用してフィルタリングおよびマッピングします。
function processArray(arr, callback) {
return arr.map(x => {
try {
return { value: callback(x) };
catch (e) {
} return { error: e };
};
}) }
次に、processArray()
を使用して配列 results
を作成します。
const results = processArray([1, -5, 6], throwIfNegative);
.deepEqual(results, [
assertvalue: 1 },
{ error: new Error('Illegal value: -5') },
{ value: 6 },
{ ;
])
function throwIfNegative(value) {
if (value < 0) {
throw new Error('Illegal value: '+value);
}return value;
}
これで、.flatMap()
を使用して、results
から値のみ、またはエラーのみを抽出できます。
const values = results.flatMap(
=> result.value ? [result.value] : []);
result .deepEqual(values, [1, 6]);
assert
const errors = results.flatMap(
=> result.error ? [result.error] : []);
result .deepEqual(errors, [new Error('Illegal value: -5')]); assert
配列メソッド .map()
は、各入力配列要素を1つの出力要素にマッピングします。しかし、複数の出力要素にマッピングしたい場合はどうすればよいでしょうか?
次の例で必要になります。
> stringsToCodePoints(['many', 'a', 'moon'])['m', 'a', 'n', 'y', 'a', 'm', 'o', 'o', 'n']
文字列の配列をUnicode文字(コードポイント)の配列に変換します。次の関数は、.flatMap()
を使用してこれを実現します。
function stringsToCodePoints(strs) {
return strs.flatMap(str => Array.from(str));
}
.flatMap()
は次のように実装できます。注: この実装は、組み込みバージョンよりもシンプルです。組み込みバージョンは、たとえば、より多くのチェックを実行します。
function flatMap(arr, mapFunc) {
const result = [];
for (const [index, elem] of arr.entries()) {
const x = mapFunc(elem, index, arr);
// We allow mapFunc() to return non-Arrays
if (Array.isArray(x)) {
.push(...x);
resultelse {
} .push(x);
result
}
}return result;
}
練習問題:
.flatMap()
exercises/arrays/convert_to_numbers_test.mjs
exercises/arrays/replace_objects_test.mjs
.filter()
: 要素の一部のみを保持する配列メソッド .filter()
は、コールバック関数が真偽値を返すすべての要素を収集した配列を返します。
例:
> [-1, 2, 5, -7, 6].filter(x => x >= 0)[ 2, 5, 6 ]
> ['a', 'b', 'c', 'd'].filter((_x,i) => (i%2)===0)[ 'a', 'c' ]
.filter()
は、次のように実装できます。
function filter(arr, filterFunc) {
const result = [];
for (const [i, x] of arr.entries()) {
if (filterFunc(x, i, arr)) {
.push(x);
result
}
}return result;
}
練習問題:
.filter()
を使用した空行の削除
exercises/arrays/remove_empty_lines_filter_test.mjs
.reduce()
: 配列からの値の導出(上級)メソッド .reduce()
は、配列 arr
の「サマリー」を計算するための強力なツールです。サマリーはあらゆる種類の値にすることができます。
arr
のすべての要素の合計。arr
のコピー。reduce
は、関数型プログラミングでは foldl
(「fold left」)としても知られており、そこで人気があります。ただし、コードを理解しにくくする可能性があるという注意点があります。
.reduce()
の型シグネチャは次のとおりです(Array<T>
内)。
.reduce<U>(
: (accumulator: U, element: T, index: number, array: T[]) => U,
callback?: U)
init: U
T
は配列要素の型、U
はサマリーの型です。両者は異なる場合もあれば異なる場合もあります。accumulator
は「サマリー」の別の名前です。
配列 arr
のサマリーを計算するために、.reduce()
はすべての配列要素をコールバック関数に一度に1つずつ渡します。
const accumulator_0 = callback(init, arr[0]);
const accumulator_1 = callback(accumulator_0, arr[1]);
const accumulator_2 = callback(accumulator_1, arr[2]);
// Etc.
callback
は、以前に計算されたサマリー(パラメータ accumulator
に格納)と現在の配列要素を組み合わせ、次の accumulator
を返します。.reduce()
の結果は、最終的な accumulator
です。つまり、すべての要素を処理した後の callback
の最後の結果です。
言い換えれば: callback
が大部分の作業を行い、.reduce()
はそれを便利な方法で呼び出すだけです。
コールバック関数が配列要素をアキュムレータに折り畳むと言うことができます。そのため、この操作は関数型プログラミングでは「fold」と呼ばれています。
.reduce()
の動作の例を見てみましょう。関数 addAll()
は、配列 arr
のすべての数値の合計を計算します。
function addAll(arr) {
const startSum = 0;
const callback = (sum, element) => sum + element;
return arr.reduce(callback, startSum);
}.equal(addAll([1, 2, 3]), 6); // (A)
assert.equal(addAll([7, -4, 2]), 5); assert
この場合、アキュムレータには、callback
が既に処理したすべての配列要素の合計が格納されます。
行Aの配列からどのようにして結果6
が導き出されたのでしょうか? callback
の次の呼び出しによって行われます。
callback(0, 1) --> 1
callback(1, 2) --> 3
callback(3, 3) --> 6
注記
.reduce()
の引数 init
から始まります)。callback
の最後の結果も、.reduce()
の結果です。あるいは、for-of
ループを使用して addAll()
を実装することもできます。
function addAll(arr) {
let sum = 0;
for (const element of arr) {
= sum + element;
sum
}return sum;
}
どちらの実装が「優れている」か断言するのは難しいです。.reduce()
ベースの実装の方が少し簡潔ですが、for-of
ベースの実装の方が、特に関数型プログラミングに慣れていない人にとっては少し理解しやすいでしょう。
.reduce()
を使用したインデックスの検索次の関数は、配列メソッド .indexOf()
の実装です。指定された searchValue
が配列 arr
内に出現する最初のインデックスを返します。
const NOT_FOUND = -1;
function indexOf(arr, searchValue) {
return arr.reduce(
, elem, index) => {
(resultif (result !== NOT_FOUND) {
// We have already found something: don’t change anything
return result;
else if (elem === searchValue) {
} return index;
else {
} return NOT_FOUND;
},
};
NOT_FOUND)
}.equal(indexOf(['a', 'b', 'c'], 'b'), 1);
assert.equal(indexOf(['a', 'b', 'c'], 'x'), -1); assert
.reduce()
の1つの制限は、早期に終了できないことです(for-of
ループでは、break
を使用できます)。ここでは、見つけたらすぐに結果を返します。
関数 double(arr)
は、要素がすべて2倍された inArr
のコピーを返します。
function double(inArr) {
return inArr.reduce(
, element) => {
(outArr.push(element * 2);
outArrreturn outArr;
,
};
[])
}.deepEqual(
assertdouble([1, 2, 3]),
2, 4, 6]); [
初期値 []
を変更して要素を追加します。破壊的でない、より関数的な double()
のバージョンを以下に示します。
function double(inArr) {
return inArr.reduce(
// Don’t change `outArr`, return a fresh Array
, element) => [...outArr, element * 2],
(outArr;
[])
}.deepEqual(
assertdouble([1, 2, 3]),
2, 4, 6]); [
このバージョンはよりエレガントですが、速度が遅く、メモリ消費量も多くなります。
練習問題:
.reduce()
map()
via .reduce()
: exercises/arrays/map_via_reduce_test.mjs
filter()
via .reduce()
: exercises/arrays/filter_via_reduce_test.mjs
countMatches()
via .reduce()
: exercises/arrays/count_matches_via_reduce_test.mjs
.sort()
: 配列のソート.sort()
の型定義は次のとおりです。
sort(compareFunc?: (a: T, b: T) => number): this
デフォルトでは、.sort()
は要素の文字列表現をソートします。これらの表現は <
を使用して比較されます。この演算子は、辞書順で比較します(最初の文字が最も重要です)。数値をソートする場合に確認できます。
> [200, 3, 10].sort()[ 10, 200, 3 ]
自然言語の文字列をソートする場合、コードユニット値(文字コード)に従って比較されることに注意する必要があります。
> ['pie', 'cookie', 'éclair', 'Pie', 'Cookie', 'Éclair'].sort()[ 'Cookie', 'Pie', 'cookie', 'pie', 'Éclair', 'éclair' ]
アクセントのないすべての大文字は、アクセントのないすべての子音の前に、アクセント付きの文字の前にきます。適切な自然言語ソートが必要な場合は、JavaScript国際化API の Intl
を使用できます。
.sort()
は、**インプレース**でソートします。レシーバ(元の配列)を変更して返します。
> const arr = ['a', 'c', 'b'];
> arr.sort() === arrtrue
> arr[ 'a', 'b', 'c' ]
パラメータ compareFunc
を使用してソート順をカスタマイズできます。これは、次の数値を返す必要があります。
a < b
の場合、負の数a === b
の場合、ゼロa > b
の場合、正の数 これらの規則を覚えるためのヒント
負の数はゼロより小さいです(など)。
このヘルパー関数を使用して数値をソートできます。
function compareNumbers(a, b) {
if (a < b) {
return -1;
else if (a === b) {
} return 0;
else {
} return 1;
}
}.deepEqual(
assert200, 3, 10].sort(compareNumbers),
[3, 10, 200]); [
以下は、迅速で簡単な代替手段です。
> [200, 3, 10].sort((a,b) => a - b)[ 3, 10, 200 ]
このアプローチの欠点は次のとおりです。
a-b
が大きな正の数または負の数になると、数値オーバーフローまたはアンダーフローのリスクがあります。オブジェクトをソートする場合も、比較関数を使用する必要があります。例として、次のコードは、年齢でオブジェクトをソートする方法を示しています。
const arr = [ {age: 200}, {age: 3}, {age: 10} ];
.deepEqual(
assert.sort((obj1, obj2) => obj1.age - obj2.age),
arrage: 3 }, { age: 10 }, { age: 200 }] ); [{
練習問題: 名前でオブジェクトをソートする
exercises/arrays/sort_objects_test.mjs
Array
凡例
R
: メソッドは配列を変更しません(非破壊的)。W
: メソッドは配列を変更します(破壊的)。new Array()
new Array(n)
は、n
個の穴を含む長さ n
の配列を作成します。
// Trailing commas are always ignored.
// Therefore: number of commas = number of holes
.deepEqual(new Array(3), [,,,]); assert
new Array()
は空の配列を作成します。ただし、代わりに常に []
を使用することをお勧めします。
Array
の静的メソッドArray.from<T>(iterable: Iterable<T> | ArrayLike<T>): T[]
[ES6]
Array.from<T,U>(iterable: Iterable<T> | ArrayLike<T>, mapFunc: (v: T, k: number) => U, thisArg?: any): U[]
[ES6]
反復可能オブジェクトまたは配列のようなオブジェクト を配列に変換します。オプションで、入力値は出力配列に追加される前に mapFunc
を使用して変換できます。
例
> Array.from(new Set(['a', 'b'])) // iterable[ 'a', 'b' ]
> Array.from({length: 2, 0:'a', 1:'b'}) // Array-like object[ 'a', 'b' ]
Array.of<T>(...items: T[]): T[]
[ES6]
この静的メソッドは、主に Array
のサブクラスで役立ち、カスタム配列リテラルとして機能します。
class MyArray extends Array {}
.equal(
assert.of('a', 'b') instanceof MyArray, true); MyArray
Array.prototype
のメソッド.at(index: number): T | undefined
[R, ES2022]
index
にある配列要素を返します。index
が負の場合、使用される前に .length
に追加されます(-1
は this.length-1
になりますなど)。
> ['a', 'b', 'c'].at(0)'a'
> ['a', 'b', 'c'].at(-1)'c'
.concat(...items: Array<T[] | T>): T[]
[R, ES3]
レシーバとすべてのitems
を連結した新しいArrayを返します。Array以外の引数(以下の例での'b'
など)は、単一要素を持つArrayとして扱われます。
> ['a'].concat('b', ['c', 'd'])[ 'a', 'b', 'c', 'd' ]
.copyWithin(target: number, start: number, end=this.length): this
[W, ES6]
start
から(含む)end
まで(含まない)のインデックス範囲の要素を、target
から始まるインデックスにコピーします。重複も正しく処理されます。
> ['a', 'b', 'c', 'd'].copyWithin(0, 2, 4)[ 'c', 'd', 'c', 'd' ]
start
またはend
が負数の場合は、.length
が加算されます。
.entries(): Iterable<[number, T]>
[R, ES6]
[インデックス、要素]のペアを反復処理するイテラブルを返します。
> Array.from(['a', 'b'].entries())[ [ 0, 'a' ], [ 1, 'b' ] ]
.every(callback: (value: T, index: number, array: Array<T>) => boolean, thisArg?: any): boolean
[R, ES5]
すべての要素に対してcallback
が真の値を返す場合、true
を返します。そうでない場合はfalse
を返します。偽の値を受け取るとすぐに停止します。このメソッドは、数学における全称量化(「すべて」、「∀」)に対応します。
> [1, 2, 3].every(x => x > 0)true
> [1, -2, 3].every(x => x > 0)false
関連メソッド:.some()
(「存在する」)。
.fill(value: T, start=0, end=this.length): this
[W, ES6]
start
から(含む)end
まで(含まない)の各インデックスにvalue
を代入します。
> [0, 1, 2].fill('a')[ 'a', 'a', 'a' ]
注意点:オブジェクトobj
でArrayを埋めるためにこのメソッドを使用しないでください。各要素はobj
を参照することになり(共有することになります)。この場合は、Array.from()
を使用する方が良いです。
.filter(callback: (value: T, index: number, array: Array<T>) => any, thisArg?: any): T[]
[R, ES5]
callback
が真の値を返す要素のみを含むArrayを返します。
> [1, -2, 3].filter(x => x > 0)[ 1, 3 ]
.find(predicate: (value: T, index: number, obj: T[]) => boolean, thisArg?: any): T | undefined
[R, ES6]
結果は、predicate
が真の値を返す最初の要素です。そのような要素がない場合は、結果はundefined
です。
> [1, -2, 3].find(x => x < 0)-2
> [1, 2, 3].find(x => x < 0)undefined
.findIndex(predicate: (value: T, index: number, obj: T[]) => boolean, thisArg?: any): number
[R, ES6]
結果は、predicate
が真の値を返す最初の要素のインデックスです。そのような要素がない場合は、結果は-1
です。
> [1, -2, 3].findIndex(x => x < 0)1
> [1, 2, 3].findIndex(x => x < 0)-1
.flat(depth = 1): any[]
[R, ES2019]
Arrayを「平坦化」します。入力Arrayの中にネストされたArrayに降りていき、レベルdepth
以下のすべての値が最上位レベルに移動されたコピーを作成します。
> [ 1,2, [3,4], [[5,6]] ].flat(0) // no change[ 1, 2, [3,4], [[5,6]] ]
> [ 1,2, [3,4], [[5,6]] ].flat(1)[1, 2, 3, 4, [5,6]]
> [ 1,2, [3,4], [[5,6]] ].flat(2)[1, 2, 3, 4, 5, 6]
.flatMap<U>(callback: (value: T, index: number, array: T[]) => U|Array<U>, thisValue?: any): U[]
[R, ES2019]
元のArrayの各要素に対してcallback()
を呼び出し、返されたArrayを連結することで結果が生成されます。
> ['a', 'b', 'c'].flatMap(x => [x,x])[ 'a', 'a', 'b', 'b', 'c', 'c' ]
> ['a', 'b', 'c'].flatMap(x => [x])[ 'a', 'b', 'c' ]
> ['a', 'b', 'c'].flatMap(x => [])[]
.forEach(callback: (value: T, index: number, array: Array<T>) => void, thisArg?: any): void
[R, ES5]
各要素に対してcallback
を呼び出します。
'a', 'b'].forEach((x, i) => console.log(x, i))
[
// Output:
// 'a', 0
// 'b', 1
通常、for-of
ループの方が良い選択肢です。高速で、break
をサポートし、任意のイテラブルを反復処理できます。
.includes(searchElement: T, fromIndex=0): boolean
[R, ES2016]
レシーバに値がsearchElement
である要素がある場合はtrue
を、そうでない場合はfalse
を返します。インデックスfromIndex
から検索を開始します。
> [0, 1, 2].includes(1)true
> [0, 1, 2].includes(5)false
.indexOf(searchElement: T, fromIndex=0): number
[R, ES5]
searchElement
と厳密に等しい最初の要素のインデックスを返します。そのような要素がない場合は-1
を返します。インデックスfromIndex
から検索を開始し、次に高いインデックスを調べます。
> ['a', 'b', 'a'].indexOf('a')0
> ['a', 'b', 'a'].indexOf('a', 1)2
> ['a', 'b', 'a'].indexOf('c')-1
.join(separator = ','): string
[R, ES1]
すべての要素の文字列表現を連結して、separator
で区切った文字列を作成します。
> ['a', 'b', 'c'].join('##')'a##b##c'
> ['a', 'b', 'c'].join()'a,b,c'
.keys(): Iterable<number>
[R, ES6]
レシーバのキーを反復処理するイテラブルを返します。
> Array.from(['a', 'b'].keys())[ 0, 1 ]
.lastIndexOf(searchElement: T, fromIndex=this.length-1): number
[R, ES5]
searchElement
と厳密に等しい最後の要素のインデックスを返します。そのような要素がない場合は-1
を返します。インデックスfromIndex
から検索を開始し、次に低いインデックスを調べます。
> ['a', 'b', 'a'].lastIndexOf('a')2
> ['a', 'b', 'a'].lastIndexOf('a', 1)0
> ['a', 'b', 'a'].lastIndexOf('c')-1
.map<U>(mapFunc: (value: T, index: number, array: Array<T>) => U, thisArg?: any): U[]
[R, ES5]
新しいArrayを返します。各要素は、レシーバの対応する要素にmapFunc
を適用した結果です。
> [1, 2, 3].map(x => x * 2)[ 2, 4, 6 ]
> ['a', 'b', 'c'].map((x, i) => i)[ 0, 1, 2 ]
.pop(): T | undefined
[W, ES3]
レシーバの最後の要素を削除して返します。つまり、レシーバの末尾をスタックとして扱います。.push()
の逆です。
> const arr = ['a', 'b', 'c'];
> arr.pop()'c'
> arr[ 'a', 'b' ]
.push(...items: T[]): number
[W, ES3]
レシーバの末尾に0個以上のitems
を追加します。つまり、レシーバの末尾をスタックとして扱います。戻り値は変更後のレシーバの長さです。.pop()
の逆です。
> const arr = ['a', 'b'];
> arr.push('c', 'd')4
> arr[ 'a', 'b', 'c', 'd' ]
スプレッド構文(...
)を使用して、Arrayをpushできます。
> const arr = ['x'];
> arr.push(...['y', 'z'])3
> arr[ 'x', 'y', 'z' ]
.reduce<U>(callback: (accumulator: U, element: T, index: number, array: T[]) => U, init?: U): U
[R, ES5]
このメソッドはレシーバのサマリーを作成します。すべてのArray要素をcallback
に渡し、現在のサマリー(accumulator
パラメータ)と現在のArray要素を組み合わせ、次のaccumulator
を返します。
const accumulator_0 = callback(init, arr[0]);
const accumulator_1 = callback(accumulator_0, arr[1]);
const accumulator_2 = callback(accumulator_1, arr[2]);
// Etc.
.reduce()
の結果は、すべてのArray要素を処理した後のcallback
の最後の結果です。
> [1, 2, 3].reduce((accu, x) => accu + x, 0)6
> [1, 2, 3].reduce((accu, x) => accu + String(x), '')'123'
init
が指定されていない場合、インデックス0のArray要素が使用され、インデックス1の要素が最初に処理されます。したがって、Arrayの長さは少なくとも1以上である必要があります。
.reduceRight<U>(callback: (accumulator: U, element: T, index: number, array: T[]) => U, init?: U): U
[R, ES5]
.reduce()
と同様に動作しますが、最後の要素から始まるArray要素を逆順に処理します。
> [1, 2, 3].reduceRight((accu, x) => accu + String(x), '')'321'
.reverse(): this
[W, ES1]
レシーバの要素を逆順に並べ替え、レシーバを返します。
> const arr = ['a', 'b', 'c'];
> arr.reverse()[ 'c', 'b', 'a' ]
> arr[ 'c', 'b', 'a' ]
.shift(): T | undefined
[W, ES3]
レシーバの最初の要素を削除して返します。.unshift()
の逆です。
> const arr = ['a', 'b', 'c'];
> arr.shift()'a'
> arr[ 'b', 'c' ]
.slice(start=0, end=this.length): T[]
[R, ES3]
レシーバのインデックスがstart
から(含む)end
まで(含まない)の要素を含む新しいArrayを返します。
> ['a', 'b', 'c', 'd'].slice(1, 3)[ 'b', 'c' ]
> ['a', 'b'].slice() // shallow copy[ 'a', 'b' ]
負のインデックスが許可されており、.length
に加算されます。
> ['a', 'b', 'c'].slice(-2)[ 'b', 'c' ]
.some(callback: (value: T, index: number, array: Array<T>) => boolean, thisArg?: any): boolean
[R, ES5]
少なくとも1つの要素に対してcallback
が真の値を返す場合、true
を返します。そうでない場合はfalse
を返します。真の値を受け取るとすぐに停止します。このメソッドは、数学における存在量化(「存在する」、「∃」)に対応します。
> [1, 2, 3].some(x => x < 0)false
> [1, -2, 3].some(x => x < 0)true
関連メソッド:.every()
(「すべて」)。
.sort(compareFunc?: (a: T, b: T) => number): this
[W, ES1]
レシーバをソートして返します。デフォルトでは、要素の文字列表現をソートします。辞書順で、文字のコード単位値(文字コード)に従ってソートします。
> ['pie', 'cookie', 'éclair', 'Pie', 'Cookie', 'Éclair'].sort()[ 'Cookie', 'Pie', 'cookie', 'pie', 'Éclair', 'éclair' ]
> [200, 3, 10].sort()[ 10, 200, 3 ]
compareFunc
を使用してソート順をカスタマイズできます。これは、以下の数値を返します。
a < b
の場合、負の数a === b
の場合、ゼロa > b
の場合、正の数数値をソートするためのトリック(数値オーバーフローまたはアンダーフローのリスクがあります)
> [200, 3, 10].sort((a, b) => a - b)[ 3, 10, 200 ]
.sort()
は安定しています
ECMAScript 2019以降、ソートは安定していることが保証されています。要素がソートによって等しいとみなされる場合、ソートはその要素の順序(互いに対する)を変更しません。
.splice(start: number, deleteCount=this.length-start, ...items: T[]): T[]
[W, ES3]
インデックスstart
で、deleteCount
個の要素を削除し、items
を挿入します。削除された要素を返します。
> const arr = ['a', 'b', 'c', 'd'];
> arr.splice(1, 2, 'x', 'y')[ 'b', 'c' ]
> arr[ 'a', 'x', 'y', 'd' ]
start
は負にすることができ、負の場合は.length
に加算されます。
> ['a', 'b', 'c'].splice(-2, 2)[ 'b', 'c' ]
.toString(): string
[R, ES1]
String()
を使用してすべての要素を文字列に変換し、コンマで区切って連結し、結果を返します。
> [1, 2, 3].toString()'1,2,3'
> ['1', '2', '3'].toString()'1,2,3'
> [].toString()''
.unshift(...items: T[]): number
[W, ES3]
レシーバの先頭にitems
を挿入し、この変更後の長さを返します。
> const arr = ['c', 'd'];
> arr.unshift('e', 'f')4
> arr[ 'e', 'f', 'c', 'd' ]
.values(): Iterable<T>
[R, ES6]
レシーバの値を反復処理するイテラブルを返します。
> Array.from(['a', 'b'].values())[ 'a', 'b' ]
クイズ
クイズアプリを参照してください。