このページではArrayオブジェクトのforEachメソッドの解説をしています。
forEachメソッドと似ている、
通常のfor文、
for...in文、
for...of文
については各リンク先ページで解説しているのでそちらを参照してください。
forEach(Array、配列)
このページでは豊富な例を用いてJavaScript(js)のArrayオブジェクトのforEachメソッドの使い方を学ぶことができます。
JavaScript(js)のforEachメソッドはArrayオブジェクト(配列)のメソッドの1つです。 第1引数として指定するコールバック関数を配列の各要素に対して実行します。
コールバック関数が実行される要素は配列に定義されている順番です。(インデックスの昇順)
// 記述例
array.forEach(コールバック関数, コールバック関数内でのthis(任意));
出典:構文 - Array.prototype.forEach() - MDN web docs
TL;DR
基本
// Arrayオブジェクト(配列)の各要素に対してコールバック関数を実行する
// コールバック関数の第1引数には各要素が代入される
const array1 = ['js', 'javascript', 'typescript'];
const callback1 = function (element) {
console.log(element);
};
const returnValue1 = array1.forEach(callback1);
==> js
==> javascript
==> typescript
// 返り値はundefined
console.log(returnValue1);
==> undefined
// アロー関数の場合
const array2 = ['js', 'javascript', 'typescript'];
array2.forEach((element) => {
console.log(element);
});
==> js
==> javascript
==> typescript
// オブジェクトの配列
const array3 = [{ name: 'Oliver' }, { name: 'Alice' }];
array3.forEach(element => {
console.log(element);
// 副作用を発生させる
element.age = 11;
});
==> { name: 'Oliver' }
==> { name: 'Alice' }
console.log(array3);
==> [ { name: 'Oliver', age: 11 }, { name: 'Alice', age: 11 } ]
// まばらな配列の場合
const array4 = [100, , 300];
console.log(array4);
==> [ 100, <1 empty item>, 300 ]
// forEach
array4.forEach(e => console.log(e));
==> 100
==> 300
// for...of
for (const p of array4) {
console.log(p);
}
==> 100
==> undefined
==> 300
// 空配列の場合
[].forEach(e => console.log(e));
==> 出力なし
// Arrayオブジェクトでないとエラー
const object1 = { a: 'A', b: 'B' };
object1.forEach(e => console.log(e));
==> TypeError: object1.forEach is not a function
インデックスの取得
// コールバック関数の第2引数を指定することで現在の要素のインデックスを取得できる
const array1 = [true, false];
const callback1 = (element, index) => {
console.log(index + ':' + element);
};
array1.forEach(callback1);
==> 0:true
==> 1:false
const array2 = ['js', 'JavaScript'];
array2.forEach((e, i) => {
console.log(`array2[${i}] = ${array2[i]}`);
});
==> array2[0] = js
==> array2[1] = JavaScript
呼び出し元配列の取得
// コールバック関数の第3引数を指定することでforEachメソッドを呼び出している配列を取得できる
const array1 = ['js', 'javascript'];
array1.forEach((element, index, array) => {
console.log(array);
});
==> [ 'js', 'javascript' ]
==> [ 'js', 'javascript' ]
// 副作用を発生させる
const array2 = ['js', 'javascript'];
array2.forEach((element, index, array) => {
array[index] = element + '!!';
});
console.log(array2);
==> [ 'js!!', 'javascript!!' ]
配列がループ中に変更された場合
// 配列の長さが変わった際は要素の位置が繰り上がり処理される
const array1 = ['js', 'Foo', 'Bar', 'Ninja'];
array1.forEach((element, index) => {
console.log(index, element);
if (element === 'Foo') {
// array1の先頭の要素を削除
array1.shift();
}
});
==> 0 js
==> 1 Foo
==> 2 Ninja
console.log(array1);
==> [ 'Foo', 'Bar', 'Ninja' ]
continue, break, returnの挙動
// continueを使用する場合
const array1 = [0, 1, 2];
array1.forEach(e => {
if (e === 1) {
continue;
}
console.log(e);
});
==> SyntaxError: Illegal continue statement: no surrounding iteration statement
// breakを使用する場合
const array2 = [0, 1, 2];
array2.forEach(e => {
if (e === 1) {
break;
}
console.log(e);
});
==> SyntaxError: Illegal break statement
// returnを使用する場合
const array3 = [0, 1, 2];
array3.forEach(e => {
if (e === 1) {
return;
}
console.log(e);
});
==> 0
==> 2
非同期処理の扱い
// 非同期関数を定義
const asyncSum = async (a, b) => {
return a + b;
};
// forEachメソッドは同期処理を前提としているため非同期処理を扱えない
const array1 = [100, 200, 300];
let sum = 0;
array1.forEach(async (element) => {
sum = await asyncSum(sum, element);
});
console.log(sum);
==> 0
// 非同期処理をするために、一例としてfor...of文を使用する
sum = 0;
const func1 = async () => {
for (const element of array1) {
sum = await asyncSum(sum, element);
}
console.log(sum);
};
func1().then(() => {
console.log('done');
});
==> 600
==> done
コールバック関数内でのthis指定
// forEachメソッドの第2引数を与えることで、コールバック関数内でのthisを指定できる
const array1 = ['js', 'ts'];
const object1 = { js: 'javascript', ts: 'typescript' };
array1.forEach(function (element) {
console.log(this);
console.log(this[element]);
}, object1);
==> { js: 'javascript', ts: 'typescript' }
==> javascript
==> { js: 'javascript', ts: 'typescript' }
==> typescript
解説
// 記述例
array.forEach(コールバック関数, コールバック関数内でのthis(任意));
出典:構文 - Array.prototype.forEach() - MDN web docs
基本
forEachメソッドはArrayオブジェクト(配列)のメソッドの1つです。
「forEachメソッドの第1引数には関数」を指定し、呼び出し元の配列の各要素に対してこの関数(コールバック関数、関数の引数として与えられる関数)が実行されます。
要素へのコールバック関数の実行順序は配列に定義されている順序です。(配列のインデックスの昇順)
「コールバック関数の第1引数」を指定すると、配列の各要素を取得することができます。
forEachメソッドはあくまでArrayオブジェクトのメソッドであり、他のオブジェクトに対しては使用できません。 名前や処理が似ている for文、 for...in文、 for...of文 などと区別して使用してください。
const array1 = [100, 200, 300];
const returnValue1 = array1.forEach(function (element) {
console.log(element);
});
==> 100
==> 200
==> 300
// 返り値はundefined
console.log(returnValue1);
==> undefined
// コールバック関数をアロー関数で記述する
const array2 = ['JS', 'TS'];
array2.forEach((element) => {
console.log(element);
});
==> JS
==> TS
// まばらな配列
const array3 = [0, , 2];
// forEach
array3.forEach(e => console.log(e));
==> 0
==> 2
// for...of
for (const e of array3) {
console.log(e);
}
==> 0
==> undefined
==> 2
// 空配列の場合
[].forEach(e => {
console.log('!!!');
console.log(e);
});
==> 出力なし
// Arrayオブジェクトでないとエラー
const string1 = 'JavaScript';
string1.forEach((e) => console.log(e));
==> TypeError: string1.forEach is not a function
インデックスの取得
「コールバック関数の第2引数」を指定すると、処理している要素の配列内でのインデックスを取得することができます。
const array1 = ['Foo', 'Bar', 'Ninja'];
array1.forEach((element, index) => {
console.log(index, element);
});
==> 0 Foo
==> 1 Bar
==> 2 Ninja
呼び出し元配列の取得
「コールバック関数の第3引数」を指定すると、forEachメソッドを呼び出した配列を取得することができます。
「コールバック関数の第3引数」で取得した配列の要素への変更は「呼び出し元の配列」に副作用を発生させることに注意してください。
const array1 = [100, 200];
array1.forEach(function (e, i, array) {
console.log(array);
});
==> [ 100, 200 ]
==> [ 100, 200 ]
// 副作用を発生させる
const array2 = [100, 200];
array2.forEach(function (e, i, array) {
array[i] = e * e;
});
console.log(array2);
==> [ 10000, 40000 ]
配列がループ中に変更された場合
呼び出し元の配列がコールバック関数の実行中に変更された場合、コールバック関数が実行される要素に影響があります。
たとえば、以下のコード例ではコールバック関数実行中に呼び出し元配列の先頭の要素を削除しました。 その結果、配列内でのインデックスに対する値が変わり、変更前にインデックス値が2であった300が出力されていません。
呼び出し元配列を変更する際はこのような挙動に注意してください。
// forEachの処理中に先頭の要素を削除する
const array1 = [100, 200, 300, 400];
array1.forEach((element, index) => {
console.log(index, element);
if (element === 200) {
array1.shift();
}
});
==> 0 100
==> 1 200
==> 2 400
console.log(array1);
==> [ 200, 300, 400 ]
continue, break, returnの挙動
for文、for...in文、for...of文内ではcontinue
やbreak
などの構文が使用できます。
しかし、forEachメソッド内では使用できません。
continueやbreakなどの構文を使用したい場合はfor...of文を使用するなど、他の構文を利用することを検討してください。
// continueを使用する場合
const array1 = ['foo', 'bar', 'ninja'];
array1.forEach(e => {
if (e === 'bar') {
continue;
}
console.log(e);
});
==> SyntaxError: Illegal continue statement: no surrounding iteration statement
// breakを使用する場合
const array2 = ['foo', 'bar', 'ninja'];
array2.forEach(e => {
if (e === 'bar') {
break;
}
console.log(e);
});
==> SyntaxError: Illegal break statement
// returnを使用する場合
const array3 = ['foo', 'bar', 'ninja'];
array3.forEach(e => {
if (e === 'bar') {
return;
}
console.log(e);
});
==> foo
==> ninja
非同期処理の扱い
forEachメソッドはPromise(プロミス)を持たないため、コールバック関数として非同期な関数・処理を指定すると期待した挙動にならないことがあります。
ループ中に非同期な処理を実現したい場合、 for...of文 などの使用を検討してください。
// 非同期関数の定義
const asyncAddBang = async (element) => {
return element + '!';
};
// forEachメソッドは同期処理を前提としているため非同期処理を扱えない
const array1 = ['js', 'javascript', 'typescript'];
let string1 = '!';
array1.forEach(async (element) => {
string1 += await asyncAddBang(element);
});
console.log(string1);
==> !
// 非同期処理をするために、一例としてfor...of文を使用する
string1 = '!';
const func1 = async () => {
for (const element of array1) {
string1 += await asyncAddBang(element);
}
console.log(string1);
};
func1().then(() => {
console.log('done');
});
==> !js!javascript!typescript!
==> done
コールバック関数内でのthis指定
forEachメソッドの第2引数に値を指定することで、第1引数で与えた関数内で使用するthis
を指定することができます。
しかし、アロー関数を第1引数に指定した場合はthis
はコンテキストによって決定されることに注意してください。
// forEachメソッドの第2引数を与えることで、コールバック関数内でのthisを指定できる
const array1 = [0, 1];
const object1 = { 0: 'zero', 1: 'one' };
array1.forEach(function (e) {
console.log(this);
console.log(this[e]);
}, object1);
==> { '0': 'zero', '1': 'one' }
==> zero
==> { '0': 'zero', '1': 'one' }
==> one