JSのコールバック関数について勘違いしていたので、勉強し直したことをメモとして残します。
こんなところで引っかかってるやつもいるんだなと知ってもらえれば幸いです。
コールバック関数とは
定義
引数として他の関数に渡され、外側の関数の中で呼び出されて、何らかのルーチンやアクションを完了させる関数のこと
Callback function (コールバック関数) | MDN Web Docs 用語集
簡単な例
const fn1 = a => a + 1; // コールバック関数
const fn2 = (b) => b(1) * 2;
fn2(fn1) // 4
例1では確かにfn1
が外側のfn2
内で呼び出されてから実行されているため、fn1
はコールバック関数と言えます。(Chat GPTさんに確認したので間違いないはず!)
勘違い
ただ、コールバックとして使用される関数は必ずしも変数に代入(宣言)する必要はないということです。つまり、無名関数で記述することができます。私はずっと変数に代入して使うものだと思っていました。(そういう書き方をしている解説を多く見てきたので...)
const num = 1;
const fn = a => a() * 2;
fn(() => num * 3); // 6
上の例2で関数() => num * 3
は変数に代入(宣言)せず、fn
の引数として直接書かれていますが、これもコールバック関数となります。
アロー関数を使わずに書くと下のようになります。
const num = 1;
const fn = function(a) {
return a() * 2; // ()は実行するの意味
}
fn(function() { // 無名関数として記述
return num * 3;
}); // 6
冒頭でも書いているように、コールバック関数の定義は 『引数として他の関数に渡され、外側の関数の中で呼び出されて、何らかのルーチンやアクションを完了させる関数のこと』 です。
上の例2では関数fn
内で渡ってきた引数a
を実行してアクションを完了させるように()
を記述しているところがポイントになります。
間違い例
以下のコードはどれもコールバック関数を使用できていません。
// 例A
const num = 3;
const fn = a => a * 2;
fn(num + 1); // 8
// 例B
const fn1 = a => a + 1;
const fn2 = b => b * 2;
fn2(fn1(1)); // 4
// 例C
const num = 1;
const fn3 = a => a * 2;
fn3(() => num * 3); // NaN
// 例D
const num = 1;
const fn4 = a => a * 2;
fn4((() => num * 3)()); // 6
例Aはnum + 1
の結果をただfn
に渡しているだけで、これは関数ではありません。
例Bは先に実行されたfn1
の結果がfn2
に渡っているだけです。1
例Cは一見すると() => num * 3
という関数をfn3
に渡しているようですが、これは実行されず関数そのものをオブジェクトとして渡しているだけです。
例Dは() => num * 3
が即時関数として実行され、その結果が数値としてfn4
に渡っているだけで、外側の関数fn4
が呼び出している(実行している)わけではありません。
よって、どれも定義から外れています。
学んだこと
- コールバック関数は無名関数でもOK
- 関数の「実行される場所」を意識する
間違いやアドバイスなどあれば、コメントいただけると大変勉強になります。