HOWTO · JavaScript

JavaScript 関数をパラメーターとして渡す

JavaScriptでは、`greet`のように関数参照を渡すと、受け取る側に関数そのものを渡せます。一方、`greet()`と書くと関数がその場で実行され、関数ではなく戻り値が渡されます。

このページの内容

JavaScriptで関数を渡すには、greetのように関数を呼び出さず、その参照を受け取り側の関数に渡します。greet()と書くと、その場で関数が実行され、代わりに戻り値が渡されます。受け取った関数を呼び出すかどうか、いつ呼び出すかは、受け取り側の関数が決めます。渡された関数は、コールバック関数と呼ばれることもあります。この仕組みを使うと、別の関数が利用する処理を渡せます。

名前付き関数を引数として渡す

処理を個別に定義したり、再利用したりする場合は、名前付き関数が便利です。この例では、formatGreetingが関数greetと名前を受け取り、受け取った関数にその名前を渡して呼び出します。

function greet(name) {
  return "Hello, " + name + "!";
}

function formatGreeting(callback, name) {
  return callback(name);
}

const message = formatGreeting(greet, "Mina");
console.log(message);

formatGreeting(greet, "Mina")という呼び出しでは、関数参照greetと文字列"Mina"の2つの値を渡しています。受け取り側の関数内でcallback(name)を呼び出すと、greetが実行され、その結果が返されます。formatGreeting(greet("Mina"), "Mina")と書いた場合は、formatGreetingが始まる前にJavaScriptがgreetを呼び出すため、最初の引数には関数ではなく文字列が渡されます。

関数をほかの引数と一緒に渡す

関数には、通常の値と複数のコールバック関数を一緒に渡せます。受け取り側の関数は、どのコールバックを呼び出すか、どの値を渡すかを選べます。この例では、applyOperationが数値と2つの関数を受け取り、それぞれの関数を数値に適用します。

function applyOperation(value, first, second) {
  return [first(value), second(value)];
}

function double(number) {
  return number * 2;
}

function addThree(number) {
  return number + 3;
}

const results = applyOperation(4, double, addThree);
console.log(results.join(", "));

引数の順序は重要です。applyOperationの各パラメーターには、呼び出し時と同じ順序で値が渡されます。valueには4、firstにはdouble、secondにはaddThreeが渡されます。この関数は、計算した2つの値を配列で返します。APIにコールバックとオプションやデータを渡す場合も同じ考え方です。パラメーターの順序を確認し、関数を実行せず名前で渡してください。

無名関数とアロー関数をコールバックとして使う

呼び出す場所で一度だけ使う処理なら、名前付き関数を別に宣言せず、その場で定義できます。次の例では、最初のmap呼び出しに無名関数を渡し、2回目のmap呼び出しにはアロー関数を渡します。

const numbers = [1, 2, 3];

const doubled = numbers.map(function (number) {
  return number * 2;
});
const tripled = numbers.map((number) => number * 3);

console.log(doubled.join(", "));
console.log(tripled.join(", "));

この例の計算結果は、doubled.join(", ")が2, 4, 6、tripled.join(", ")が3, 6, 9です。これはコードの動作から導ける値であり、ここで実行した結果ではありません。

2, 4, 6
3, 6, 9

mapは配列の各要素に対してコールバックを呼び出し、戻り値から新しい配列を作ります。コールバックに名前を付ける必要はありません。無名関数はfunctionキーワードを使い、アロー関数は=>と、値が暗黙に返される式本体を使います。処理が分かりやすくなる形式を選んでください。アロー関数のthisは、外側のスコープから引き継がれます。コールバック自身のthisが必要な場合は、通常の関数を使い、呼び出し元のAPIが定めるthisの動作を確認してください。

関数から別の関数を返す

関数は別の関数を返すこともできます。コールバックを引数として渡す場合とは異なり、外側の関数を呼び出すと関数が作られて返されるため、保存して後から呼び出せます。たとえば、makeMultiplierは選んだ乗数を周囲のスコープに保持する関数を返します。

function makeMultiplier(multiplier) {
  return function (number) {
    return number * multiplier;
  };
}

const triple = makeMultiplier(3);
console.log(triple(5));

makeMultiplier(3)は関数を返すので、tripleはその返された関数を参照します。次にtriple(5)を呼び出すと、その関数にnumber引数が渡されます。内側の関数は、それを作成した呼び出しのmultiplierにも引き続きアクセスできます。このように外側のスコープへのアクセスが保たれる仕組みをクロージャと呼びます。高階関数とは、別の関数を受け取る関数、関数を返す関数、またはその両方を行う関数です。

よくある質問

複数の関数を渡すにはどうすればよいですか? 関数参照をそれぞれ別の引数位置に置き、コンマで区切ります。受け取り側の関数のパラメーターと同じ順序にしてください。

コールバックはいつ実行されますか? 呼び出すタイミングは受け取り側の関数が決めます。関数を渡しただけでは実行されません。受け取り側の設計に応じて、すぐに、後で、または複数回呼び出されることがあります。

関数から別の関数を返せますか? はい。外側の関数を呼び出して返された関数を受け取り、必要に応じて呼び出すか、別の場所に渡します。クロージャに設定値を保持させた関数を作るときによく使われます。