⌨️

JavaScriptの主要な反復処理をマスターする

2021/03/20に公開

概要

この記事では、JavaScriptの主要な反復処理についてまとめています。
関数型プログラミングの入口になる反復処理をしっかり理解していきたいと思います。

配列の反復処理

まずは、配列の反復処理から学びます。

map()

map()は、対象となる配列の要素ひとつひとつを任意に加工し、新しい配列を返します。

Input
const arr = [1, 2, 3, 4, 5, 6, 7, 8, 9];

cosnt newArr = arr.map((n) => n * 2);
console.log(newArr);
Output
[ 2, 4, 6, 8, 10, 12, 14, 16, 18 ]

上記の例のコードでは、mapメソッドを用いて、各要素を2倍した配列を返しています。
補足を入れると(n) => n * 2の処理は1行で書かれているので、returnが省略されています。

filter()

filter()は、与えた条件に適合する要素だけを抽出した新しい配列を返します。

Input
const arr = [1, 2, 3, 4, 5, 6, 7, 8, 9];

cosnt newArr = arr.filter((n) => n % 3 === 0);
console.log(newArr);
Output
[3,6,9]

n % 3 === 0という条件により、3の倍数(3で割り切れる数)だけの配列を返しています。

find()

find()は与えた条件を満たした最初の要素を返します。要素内に条件を満たすものが存在しなかった場合は、undefindを返します。

Input
const arr = [1, 2, 3, 4, 5, 6, 7, 8, 9];

console.log(arr.find((n) => n > 5));
console.log(arr.find((n) => n > 10));
Output
6
undefind

1つ目の例の条件式は、n > 5となっており、この条件を最初にに満たすのは6なので、6が出力されています。
一方、2つ目の例では、n > 10という条件式を満たす要素が配列内にないので、undefindが出力されています。

findIndex()

findIndex()は、与えた条件を満たした最初の要素のインデックスを返します。要素内に条件を満たすものがなかった場合、-1を返します。

Input
const arr = [1, 2, 3, 4, 5, 6, 7, 8, 9];

console.log(arr.findIndex((n) => n > 5));
console.log(arr.findIndex((n) => n > 10));
Output
5
-1

ロジックはfind()と同じで、こちらはインデックス番号を返しています。

every()

every()は与えた条件を全ての要素が満たすかを真偽値で返します。

Input
const arr = [1, 2, 3, 4, 5, 6, 7, 8, 9];

console.log(arr.every((n) => n !== 0)); 
Output
true

条件はn !== 0ですので、arrの要素は0を持たないので、trueを返しています。

some()

some()は、与えた条件を満たす要素がひとつでもあるかを真偽値で返します。

Input
const arr = [1, 2, 3, 4, 5, 6, 7, 8, 9];

console.log(arr.some((n) => n >= 10));
Output
false

条件はn >= 10で配列の要素はひとつも条件を満たしていないので、falseを返します。

reduce()

reduce()は、全要素を足すときによく使われるメソッドです。
これまで紹介したメソッドと比べると、少し挙動が複雑で難しいので、例を見ながら処理の流れを追ってみます。。

Input
constarr=[1, 2, 3, 4]

result = arr.reduce((sum, num) => sum + num);
console.log(result);
Output
10

reducには2つの引数を渡します。上記の例ではsumnumが渡されています。
それぞれの引数には、以下のものが渡されます。

  • 第1引数: 前回の関数の実行結果
  • 第2引数: 配列の各要素

これを踏まえて処理の流れを見てみましょう。

  • 1回目の実行: num = 1、前回の実行結果はないので、結果は1
  • 2回目の実行: num = 2、前回の実行結果は1なのでsum = 1が入り、結果は1 + 2 = 3
  • 3回目の実行: num = 3、前回の実行結果は3なのでsum = 3が入り、結果は3 + 3 = 6
  • 4回目の実行: num = 4、前回の実行結果は3なのでsum = 6が入り、結果は4 + 6 = 10

このような流れで反復処理が実行され、最終的には最後に実行された値だけが返されます。上記の例では10と出力されています。
reduce()が返す値は、最後に返された値だけでだということには注意が必要です。

難しそうに見えますが、仕組みを知ってしまえば大したことないですね。

sort()

sort()はソート(並べ替え)を行うメソッドです。条件を満たすように配列の順序を入れ替えて、新しい配列を返します。
こちらも例を見ながら処理の流れを追って理解します。

Input
constarr=[1, 2, 3, 4, 5]

newArr = arr.sort((n, m) => n > m ? -1 : 1);
console.log(newArr);
Output
[5, 4, 3, 2, 1]

sort()は、引数として既定の「比較関数」を渡すようになっています。この比較関数が遵守しなければならないルールは次の3つです。

  1. 第1引数が第2引数より優先度が高い(前に来る)場合、-1を返す
  2. 第1引数が第2引数より優先度が低い(後ろに来る)場合、1を返す
  3. 第1引数と第2引数の優先度が同じ(ソートの必要がない)場合、0 を返す(省略可)

上記の例では、三項演算子が使われており(n, m) => n > m ? -1 : 1となっています。n > mtrueとなる場合に-1を、falseとなる場合に1が返されます。
これを全ての組み合わせで実行することで、要素が大きい順に並んだ配列が返されます。

これは結構難しいですね。

forEach()

forEach()メソッドは、配列の要素をひとつずつ取り出し、記述したコールバック関数に渡して処理を行うことができます。forEach()は、値を返しません。

const arr = [1, 2, 3, 4, 5, 6, 7, 8, 9];

arr.forEach((n) => {
  if(n % 2 === 0){
    console.log(`${n}は偶数です`);
  }
});

上記の例では、forEachにより配列の要素をひとつずつ取り出し、コールバック関数の処理を順に行なっています。
コールバック関数の処理では、if文によりn % 2 === 0と言う条件にマッチする場合に、~は偶数ですというテキストをコンソールに出力しています。

for ... of 文

for ... ofはシンプルなfor文です。forEarch()メソッドと同様に配列の要素をひとつずつ取り出し、ブロック内の処理を実行します。

const arr = [1, 2, 3, 4, 5, 6, 7, 8, 9];

for(let n of arr) {
  if(n % 2 !== 0) {
    console.log(`${n} is odd`);
  }
}

特別難しいことはないと思います。

ただ最後に紹介した2つの反復処理に関しては値を返さないため、関数型プログラミングにおいてはあまり使わない方が良いですね。

オブジェクトの反復処理

オブジェクトの反復処理ではfor ... in文が使えます。
ただこちらも値を返さない文であるという観点から、関数型プログラミングにおいてはあまり使わない方が良いです。

ここでは、Airbnbのスタイルガイドでも推奨されているObject自身が持つメソッドを使って配列を形成する方法を紹介します。

Object.keys()

Object.keys()は、オブジェクトのプロパティのキーのリストを配列で返します。こちらはES5で追加されたメソッドです。

Input
cosnt user = {
  name: 'fukumoto'
  age: 23
  company: 'UnReact'
}

console.log(Object.keys(user));
Output
['name', 'age', 'company']

userとして定義したオブジェクトのキーの配列が返されています。

Object.values()

Object.values()は、オブジェクトのプロパティの値のリストを配列で返します。こちらは、ES2017で追加されたメソッドです。

Input
cosnt user = {
  name: 'fukumoto'
  age: 23
  company: 'UnReact'
}

console.log(Object.values(user));
Output
['fukumoto', 23, 'UnReact']

userとして定義したオブジェクトの値の配列が返されています。

Object.entries()

Object.entries()は、オブジェクトのキーと値が対になった2次元配列を返します。こちらもES2017で追加されたメソッドです。

Input
cosnt user = {
  name: 'fukumoto'
  age: 23
  company: 'UnReact'
}

console.log(Object.entries(user));
Output
[
  ['name', 'fukumoto'],
  ['age', 23],
  ['company', 'UnReact']  
]

userとして定義された1組のオブジェクトのキーと値が対となった配列を一つの塊とし、さらに配列となって出力されています。このような配列を2次元配列と呼びます。

Objectのメソッドを3つ紹介しましたが、これらは配列の反復処理を行うメソッドとは使い方が異なっています。
配列はインスタンス自身がメソッドを持っていますが、オブジェクトはインスタンス自身はメソッドを持っていません。これが大きな違いです。
JavaScriptはその複雑な歴史的経緯から、このような若干不便な部分が多々あります。しょうがないですね。

JavaScriptのオブジェクトの反復処理については、上記で紹介したObjectメソッドを用いて配列を作り、それをこの記事の前半で紹介したようなメソッドで反復処理します。

#まとめ
今回は、JavaScriptの主要な反復処理についてまとめてみました。
最後まで読んでいただきありがとうございます。

GitHubで編集を提案

Discussion