From 33058f2b292b3a581333bdfb21b8f671898c5060 Mon Sep 17 00:00:00 2001 From: Peter Bengtsson Date: Tue, 8 Dec 2020 14:40:17 -0500 Subject: initial commit --- .../global_objects/array/foreach/index.html | 370 +++++++++++++++++++++ 1 file changed, 370 insertions(+) create mode 100644 files/ja/web/javascript/reference/global_objects/array/foreach/index.html (limited to 'files/ja/web/javascript/reference/global_objects/array/foreach') diff --git a/files/ja/web/javascript/reference/global_objects/array/foreach/index.html b/files/ja/web/javascript/reference/global_objects/array/foreach/index.html new file mode 100644 index 0000000000..d7328dac1b --- /dev/null +++ b/files/ja/web/javascript/reference/global_objects/array/foreach/index.html @@ -0,0 +1,370 @@ +--- +title: Array.prototype.forEach() +slug: Web/JavaScript/Reference/Global_Objects/Array/forEach +tags: + - Array + - ECMAScript 5 + - JavaScript + - Method + - Prototype + - Reference +translation_of: Web/JavaScript/Reference/Global_Objects/Array/forEach +--- +
{{JSRef}}
+ +

forEach() メソッドは与えられた関数を、配列の各要素に対して一度ずつ実行します。

+ +
{{EmbedInteractiveExample("pages/js/array-foreach.html")}}
+ + + +

構文

+ +
arr.forEach(callback(currentValue[, index[, array]]) {
+  // execute something
+}[, thisArg]);
+ +

引数

+ +
+
callback
+
各要素に対して実行するコールバック関数で、1 つから 3 つの引数を受け付けます。
+
+
+
currentValue
+
現在処理されている配列の要素です。
+
index {{optional_inline}}
+
配列内の currentValue の添字です。
+
array {{optional_inline}}
+
forEach() が呼び出されている配列です。
+
+
+
thisArg {{optional_inline}}
+
callback 内で this として使用する値です。
+
+ +

返値

+ +

undefined です。

+ +

解説

+ +

forEach() は、与えられた関数 callback を配列に含まれる各要素に対して一度ずつ、昇順で呼び出します。インデックスプロパティが削除されていたり、初期化されていなかったりした場合は呼び出されません。(疎らな配列については、下記の例を参照。)

+ +

callback は次の 3 つの引数で呼び出されます。

+ +
    +
  1. 要素の値
  2. +
  3. 要素のインデックス
  4. +
  5. 走査されている配列
  6. +
+ +

forEach()thisArg 引数が与えられると、callback の呼び出し時にそのオブジェクトが thisArg として使用されます。callback によって究極に管理される this の値は、関数から見える this を特定する一般規則に従います。

+ +

forEach() によって処理される配列要素の範囲は、callback が最初に呼び出される前に設定されます。forEach() の呼び出しが開始された後に追加された配列要素に対しては、callback は実行されません。既存の配列要素が変更または削除された場合、callback に渡される値は forEach() がそれらを参照した時点での値になります。削除された配列要素を参照することはありません。既に参照された配列要素がイテレーションの間 (e.g. {{jsxref("Array.prototype.shift()", "shift()")}}を使用して) に削除された場合、後の要素は飛ばされます。(下記の例を参照してください。)

+ +

forEach() は配列の各要素に対して callback 関数を一度ずつ実行します。{{jsxref("Array.prototype.map()", "map()")}} や {{jsxref("Array.prototype.reduce()", "reduce()")}} と異なり、返値は常に {{jsxref("undefined")}} であり、チェーンできません。チェーンの最後に副作用を生じさせるのが典型的な使用法です。

+ +

forEach() は呼び出された配列を変化させません。(ただし callback が変化させる可能性があります)

+ +
+

例外を発生する以外の方法で、forEach() ループを止めることはできません。ループ中に中断する必要がある場合、forEach() メソッドは適切な方法ではありません。

+ +

早期終了を行うには下記のような手段が適しています。

+ + + +

他の Array のメソッドである {{jsxref("Array.prototype.every()", "every()")}}, {{jsxref("Array.prototype.some()", "some()")}}, {{jsxref("Array.prototype.find()", "find()")}}, {{jsxref("Array.prototype.findIndex()", "findIndex()")}} は、配列の要素を検査する際、truthy の値を返すことで以降の繰り返しが必要であるかどうかを決めます。

+
+ +
+

forEach は同期関数を期待する

+forEach はプロミスを待ちません。forEach のコールバックとしてプロミス (または非同期関数) を使用する場合は、その意味合いを理解しておくようにしてください。 + +
コード例
+ +
let ratings = [5, 4, 5];
+let sum = 0;
+
+let sumFunction = async function (a, b)
+{
+  return a + b
+}
+
+ratings.forEach(async function(rating) {
+  sum = await sumFunction(sum, rating)
+})
+
+console.log(sum)
+// 本来期待される出力: 14
+// 実際の出力: 0
+
+
+ + +

ポリフィル

+ +

forEach() は ECMA-262 規格の第 5 版で追加されたもので、この規格のすべての実装には存在しない可能性があります。これを回避するには、スクリプトの最初に以下のコードを挿入して、ネイティブにサポートされていない実装でも forEach を使用できるようにします。

+ +

このアルゴリズムは、{{jsxref("Object")}} と {{jsxref("TypeError")}} が元の値を持ち、fun.call が {{jsxref("Function.prototype.call()")}} の元の値に評価されると仮定すると、ECMA-262 規格の第 5 版で指定されているものと全く同じです。

+ +
// Production steps of ECMA-262, Edition 5, 15.4.4.18
+// Reference: http://es5.github.io/#x15.4.4.18
+
+if (!Array.prototype['forEach']) {
+
+  Array.prototype.forEach = function(callback, thisArg) {
+
+    if (this == null) { throw new TypeError('Array.prototype.forEach called on null or undefined'); }
+
+    var T, k;
+    // 1. Let O be the result of calling toObject() passing the
+    // |this| value as the argument.
+    var O = Object(this);
+
+    // 2. Let lenValue be the result of calling the Get() internal
+    // method of O with the argument "length".
+    // 3. Let len be toUint32(lenValue).
+    var len = O.length >>> 0;
+
+    // 4. If isCallable(callback) is false, throw a TypeError exception.
+    // See: http://es5.github.com/#x9.11
+    if (typeof callback !== "function") { throw new TypeError(callback + ' is not a function'); }
+
+    // 5. If thisArg was supplied, let T be thisArg; else let
+    // T be undefined.
+    if (arguments.length > 1) { T = thisArg; }
+
+    // 6. Let k be 0
+    k = 0;
+
+    // 7. Repeat, while k < len
+    while (k < len) {
+
+      var kValue;
+
+      // a. Let Pk be ToString(k).
+      //    This is implicit for LHS operands of the in operator
+      // b. Let kPresent be the result of calling the HasProperty
+      //    internal method of O with argument Pk.
+      //    This step can be combined with c
+      // c. If kPresent is true, then
+      if (k in O) {
+
+        // i. Let kValue be the result of calling the Get internal
+        // method of O with argument Pk.
+        kValue = O[k];
+
+        // ii. Call the Call internal method of callback with T as
+        // the this value and argument list containing kValue, k, and O.
+        callback.call(T, kValue, k, O);
+      }
+      // d. Increase k by 1.
+      k++;
+    }
+    // 8. return undefined
+  };
+}
+ + + + + + +

+ +

初期化されていない値については何もしない (疎らな配列)

+ +
const arraySparse = [1,3,,7]
+let numCallbackRuns = 0
+
+arraySparse.forEach((element) => {
+  console.log(element)
+  numCallbackRuns++
+})
+
+console.log("numCallbackRuns: ", numCallbackRuns)
+
+// 1
+// 3
+// 7
+// numCallbackRuns: 3
+// 備考: 見ての通り、存在しない 3 から 7 までの値では、コールバック関数が呼び出されません。
+ +

for ループから forEach への変換

+ +
const items = ['item1', 'item2', 'item3']
+const copyItems = []
+
+// before
+for (let i = 0; i < items.length; i++) {
+  copyItems.push(items[i])
+}
+
+// after
+items.forEach(function(item){
+  copyItems.push(item)
+})
+
+ +

配列の内容の出力

+ +
+

メモ: 配列の内容をコンソールに表示するために、配列の整形済みのバージョンを表示する {{domxref("Console/table", "console.table()")}} を使用することができます。

+ +

以下の例では同じことを forEach() を使用して行う他の方法を説明しています。

+
+ +

次のコードは配列の要素ごとに、コンソールに 1 行ずつ要素の内容を出力します。

+ +
function logArrayElements(element, index, array) {
+  console.log('a[' + index + '] = ' + element)
+}
+
+// 添字が 2 のものは、配列内のその位置にアイテムが存在しない
+// ため、飛ばされていることに注意してください。
+[2, 5, , 9].forEach(logArrayElements)
+// logs:
+// a[0] = 2
+// a[1] = 5
+// a[3] = 9
+
+ +

thisArg の使用

+ +

以下の (不自然な) 例は、配列の中の各項目からオブジェクトのプロパティを更新します。

+ +
function Counter() {
+  this.sum = 0
+  this.count = 0
+}
+Counter.prototype.add = function(array) {
+  array.forEach((entry) => {
+    this.sum += entry
+    ++this.count
+  }, this)
+  // ^---- Note
+}
+
+const obj = new Counter()
+obj.add([2, 5, 9])
+obj.count
+// 3
+obj.sum
+// 16
+
+ +

thisArg 引数 (this) が forEach() に提供されているため、callback の呼び出しのたびにこれが渡されます。コールバックはこれを this の値として使用します。

+ +
+

注: コールバック関数の受け渡しにアロー関数式を使用した場合、thisArg 引数は、アロー関数が文法的に {{jsxref("Operators/this", "this")}} の値に結び付けられているため省略可能です。

+
+ +

オブジェクトをコピーする関数

+ +

次のコードは与えられたオブジェクトのコピーを生成します。

+ +

オブジェクトのコピーを生成するには他にもいくつか方法があります。次のものは一つの方法であり、Array.prototype.forEach() が ECMAScript 5 の Object.* メタプロパティ関数を使用することでどのように動作するかを説明するために示しているものです。

+ +
function copy(obj) {
+  const copy = Object.create(Object.getPrototypeOf(obj))
+  const propNames = Object.getOwnPropertyNames(obj)
+
+  propNames.forEach((name) => {
+    const desc = Object.getOwnPropertyDescriptor(obj, name)
+    Object.defineProperty(copy, name, desc)
+  })
+
+  return copy
+}
+
+const obj1 = { a: 1, b: 2 }
+const obj2 = copy(obj1) // obj2 looks like obj1 now
+
+ +

配列が繰り返しの間に変更され、他の要素が飛ばされる場合

+ +

次の例では one, two, four をログ出力します。

+ +

two を持つ項目に達した時、配列全体の最初の項目はシフトして外れ、すべての残りの項目が 1 つ上の位置に繰り上がります。four が配列の以前の位置に来るため、three が飛ばされます。

+ +

forEach() は繰り返しの前に配列のコピーを生成しません。

+ +
let words = ['one', 'two', 'three', 'four']
+words.forEach((word) => {
+  console.log(word)
+  if (word === 'two') {
+    words.shift()
+  }
+})
+// one
+// two
+// four
+
+ +

配列の平板化

+ +

次の例は学習目的だけのものです。内蔵メソッドを使用して配列を平板化したい場合は、{{jsxref("Array.prototype.flat()")}} を使用することができます (ES2019 の一部となる予定で、一部のブラウザーではすでに実装済み)。

+ +
function flatten(arr) {
+  const result = []
+
+  arr.forEach((i) => {
+    if (Array.isArray(i)) {
+      result.push(...flatten(i))
+    } else {
+      result.push(i)
+    }
+  })
+
+  return result
+}
+
+// Usage
+const nested = [1, 2, 3, [4, 5, [6, 7], 8, 9]]
+
+flatten(nested) // [1, 2, 3, 4, 5, 6, 7, 8, 9]
+
+ +

仕様

+ + + + + + + + + + + + +
仕様書
{{SpecName('ESDraft', '#sec-array.prototype.foreach', 'Array.prototype.forEach')}}
+ +

ブラウザーの互換性

+ +
+ + +

{{Compat("javascript.builtins.Array.forEach")}}

+
+ +

関連情報

+ + -- cgit v1.2.3-54-g00ecf