JavaScript
 Computer >> コンピューター >  >> プログラミング >> JavaScript

JavaScriptの高階関数(HOF)入門ガイド:基本の使い方からforEach・mapまで徹底解説

JavaScript開発者であれば、通常の関数を使ったことがあるでしょう。こうした「第一級関数(ファーストオーダー関数)」は、引数として関数を受け取らず、戻り値として関数を返すこともありません。

function hello(name) {
   return "Hello," + " " +  name
}
 
console.log(hello("Career Karma")); // Hello, Career Karma

本記事では、高階関数(HOF:Higher Order Function)について解説します。高階関数とは、関数を引数として受け取ったり、戻り値として関数を返したりすることで、コードを簡潔にし可読性を高めるための関数です。基本的な例を通じてHOFと関数型プログラミングの考え方を紹介し、さらに高階関数の仕組みを活用した2つの人気の高度な配列メソッドについても取り上げます。

高階関数の基本例

JavaScriptでは、高階関数をさまざまな形で活用できます。ここでは代表的な2つの例を見ていきましょう。

電卓(計算機)

まずは、コールバック関数を引数として受け取り、そのコールバックに引数を渡して実行する、シンプルな高階関数から始めます。

// 高階関数
function higherOrderFunction(num1, num2, cb) {
   return cb(num1, num2); // コールバック関数を呼び出し、引数を渡します
}
 
// コールバック関数
function add(num1, num2) {
   return num1 + num2;
}
function multiply(num1, num2) {
   return num1 * num2;
}
function divide(num1, num2) {
   return num1 / num2;
}
function subtract(num1, num2) {
   return num1 - num2;
}
function modulo(num1, num2) {
   return num1 % num2;
}
 
console.log(higherOrderFunction(43, 13, add));

このスニペットには2種類の関数が登場します。1つはコールバックを返す高階関数、もう1つは2つの数値に対して演算を行う第一級関数のセットです。最後の行でhigherOrderFunction()を呼び出すと、渡されたcbが指定されたパラメータで実行され、その結果が返されます。すべての算術演算子に対応するコールバック関数を用意しておけば、higherOrderFunctionを使って必要な演算を自由に呼び出せるのです。

イベントリスナー

もう一つの高階関数の身近な例が、DOM(ドキュメントオブジェクトモデル)上の要素にイベントリスナーを追加するときの挙動です。次の例を見てみましょう。

<!DOCTYPE html>
<html>
   <head>
       <meta charset="utf-8">
       <meta http-equiv="X-UA-Compatible" content="IE=edge">
       <title></title>
       <meta name="description" content="">
       <meta name="viewport" content="width=device-width, initial-scale=1">
       <link rel="stylesheet" href="">
   </head>
   <body>
       <button>Click Me!</button>
       <script async defer>
           const button = document.querySelector("button");
           button.addEventListener("click", (e) => {
               alert("The button has been clicked!");
           })
 
       </script>
   </body>
</html>

この例では、HTMLでボタンを作成し、JavaScriptでそのボタンを選択してイベントリスナーを追加しています。イベントリスナーの構造はシンプルな高階関数そのものであり、第2引数として無名関数(匿名関数)を受け取っています。

addEventListenerの部分が高階関数に該当し、クリックされたときに実行されるコールバック関数を引数として受け取っているわけです。

高度な配列メソッド

JavaScriptの組み込み配列メソッドとは、ES6で導入された特別な高階関数のことで、配列を反復処理しながら要素を操作したり、操作済みのまったく新しい配列を返したりできます。

JavaScriptでより複雑な問題解決に取り組むようになったら、配列を反復処理する際に書いていたロジックを抽象化することを意識してみましょう。これらの高階関数である配列メソッドを活用することで、より優れたJS開発者へと成長できます。

例えば、教授(professors)の名前が格納された配列があるとしましょう。

forEach

ES6以前は、配列を反復処理して各要素を操作したい場合、次のように書く必要がありました。

function forEachES5(arr){
   for(let i = 0; i < arr.length; i++) {
       arr[i] = "Professor " + arr[i];
   }
   return arr;
}
 
console.log(forEachES5(professors));

ES6の構文では、forEachメソッドを使うことでコードを大幅に簡潔にできます。

function forEachES6(arr) {
   arr.forEach((professor, index, origArr) => {
       origArr[index] = "Professor " + professor;
   });
   return arr;
}

forEachメソッドは、最初のパラメータとしてコールバック関数を受け取るため、高階関数として機能します。このコールバック関数は、配列内の各要素に対して実行される「アクション」そのものです。さらに、forEachメソッドは省略可能な第2・第3パラメータとして、インデックスと元の配列も受け取れます。

これらのパラメータの順序は重要です(他の組み込み配列メソッドも同様)。第1引数は常にコールバック関数、第2引数は常に配列内の要素のインデックス、第3引数は常に配列自体のコピーとなります。

forEachメソッドは、JavaScriptにおけるforループのもう一つの表現方法だと言えます。ただし、このメソッドは何も返しません。既存の配列を直接操作し、何をするかを指定すれば、その結果を作業中の配列に保存します。

map

forEachメソッドに最も近いのがmapメソッドです。動作は非常によく似ていますが、mapは新しい配列を返す点が大きく異なります。コールバック関数内で行った操作は、元の配列には影響しません。

ES6以前のmapがどのようなものだったか見てみましょう。

function mapES5(arr){
   let newArr = [];
   for(let i = 0; i < arr.length; i++) {
       newArr.push("Professor " + arr[i]);
   }
   return newArr;
}

ご覧のとおり、forループの外側で新しい配列を宣言し、そこに新しい値をpushする必要がありました。しかも、新しい配列を他の場所で使えるようにするには、実際にreturnする必要もあります。

ES6のmapメソッドを使えば、こうしたロジックを抽象化して、より読みやすいコードにできます。

function mapWithES6(arr) {
   const mapped = arr.map(professor => {
       return "Professor " + professor;
   })
   return mapped;
}

mapメソッドや、reduce・filterといった類似の配列メソッドの特長は、その結果を変数に代入して返したり、関数全体をそのまま返したりできる点です。新しい配列へのpushは不要で、mapメソッドが自動的に処理してくれます。ただし、mapメソッドのコールバック関数内のロジックには、必ず戻り値を含めることを忘れないでください。

まとめ

高階関数は、JavaScriptにおいて開発者としてのスキルを一段階引き上げるために非常に重要な概念です。ロジックを抽象化することでコードの可読性が高まり、場合によってはパフォーマンスの向上にもつながります。

本チュートリアルでは、基本的な計算機の例からイベントリスナー、そしてforEachやmapといった高度な配列メソッドまで、高階関数のさまざまな書き方を紹介しました。これらをマスターすれば、より複雑な問題にも自信を持って挑戦できるようになるでしょう。

  1. JavaScriptの高階関数とは?基本概念とサンプルコードをわかりやすく解説

    高階関数とは?JavaScriptでは、関数はオブジェクトとして扱われます。そのため、関数を別の関数に引数として渡したり、関数の戻り値として別の関数を返したりすることが可能です。JavaScriptの関数は「第一級関数(ファーストクラス関数)」と呼ばれ、変数・オブジェクト・配列などに自由に格納できるという特徴を持っています。そして、関数を引数として受け取る、戻り値として返す、あるいはその両方を行う関数のことを「高階関数(Higher Order Function)」と呼びます。代表的な高階関数には、map()、filter()、reduce()、forEach()などがあります。これらを活用す

  2. JavaScriptのファーストクラス関数とは?特徴と使い方を実例で解説

    ファーストクラス関数(第一級関数)とは? JavaScriptでは、関数もオブジェクトの一種として扱われます。そのため、関数を別の関数の引数(パラメータ)として渡したり、関数の中で別の関数を戻り値として返したりすることが可能です。 このような性質を持つことから、JavaScriptの関数はファーストクラス関数(第一級関数)と呼ばれています。つまり、関数は変数・オブジェクト・配列などに自由に格納できる「値」だということです。 さらに、関数を引数として受け取る、関数を戻り値として返す、あるいはその両方を行う関数は高階関数(Higher Order Function)と呼ばれます。 ファーストクラ