ywork2020.com

Title

コールバック関数について

目次 (INDEX)

コールバック関数とは

ここで説明する コールバック関数 とは次の語句からなるプログラミング用語です。
callback
読み: コールバック
意味: プログラミングにおいて、他のコードの引数として渡されるサブルーチンの意味
function
読み: ファンクション
意味: 関数、機能する、役割を果たす

目次に戻る

コールバック関数の概要

コールバック関数とは、呼び出し元の関数に呼び出され、その実行結果を呼び出し元関数の引数に渡す役割を持つ関数のことをいいます。

これは関数の入れ子と考えると、分かりやすいかもしれません。

そもそも、関数が分からない方は、先に 関数 についての説明ページを一読してください。

前述では一応のお決まりとして、「呼び出し元の関数」と表現していますが、これは関数でなくメソッドでも同じことが言えます。 つまり、呼び出し元のメソッドに呼び出され、その実行結果を引数に渡す役割を持つ関数も、コールバック関数と言えます。 また、呼び出し元のメソッドに呼び出され、その実行結果を引数に渡す役割を持つメソッドもコールバック関数、もしくはコールバックメソッドと言えるわけです。

「関数」と「メソッド」という言葉が出てきて、少し混乱するという方もいるかもしれませんので、次のセクションで関数とメソッドの違いについて簡単に触れておきます。

目次に戻る

関数とメソッドとコールバック

ここでは、関数とメソッドの違いについて少し書いておこうと思います。 また、関数のコールバックについても触れています。

そもそも、関数が分からない方は、先に 関数 についての説明ページを一読してください。 なぜなら、関数とメソッドは、基本的には同じものだからです。

関数 のページでも書いていますが、 関数とは何かというと、プログラムにおいて、「何らかの結果を返すもの」と表現できます。

なら、「メソッド」って何なの? ということになりますが、 それを単純に言うと、「メソッドも関数の一種です。」ということになります。

メソッドは、クラス内で定義された関数です。 私たちは普段、クラスのインスタンスを生成してオブジェクトを使うことが多いでしょう。 このオブジェクトから呼び出すことができる関数をメソッドと言っています。

逆にいうと単純に「関数」といっているのは、クラスに属さないで、そもそもの土台に組み込まれたもの、 または、そもそもの土台にプログラマーが打ち立てたものを指しています。

ここからは、少しコードを交えて関数やメソッドのコールバックを見ていきましょう。

まず、はじめにコールバックの最も単純な形式の例を見てみましょう。

※ このサンプルは、正確にいうとコールバック関数とはいえないですが、関数が関数を呼び出すという雰囲気をみてください。

次のコードの parseInt("10.5px") は、パースイントという組み込み関数(※)です。
(※ 厳密にいうと Window や Number など、グローバルオブジェクトのメソッドと言った方が正解かもしれませんが割愛。)

このパースイントがコールバックになります。 パースイントの処理としては引数の "10.5px" という文字列を「切捨て整数値」に変換して返すものですが、その戻り値を console.log() の引数に指定しているわけです。

<script>
	console.log( parseInt("10.5px") );				
</script>

次のコードでは、mySum(arguments) という自作関数を打ち立てています。
この関数は引数に与えられた数値配列の合計を返す仕様にしています。

この mySum() が呼び出し元の関数となります。 この mySum() の内部処理には forEach() メソッドが使われており、これも1つのコールバック関数と言えます。 また、forEach() の引数には 無名関数の戻り値が使われているので、関数とメソッドの多重な入れ子状態が見て取れると思います。

<script>
	function mySum(arguments){
		let sumA = 0;
		arguments.forEach(function(element){
			sumA = sumA + element;
		});
		return sumA;
	}
	console.log( mySum([1,2,3]) );				
</script>

コードを見て、いかがだったでしょうか。 私たちは知らず知らずのうちに、コールバックを多用しているのですが、いざ 「コールバック関数」 という言葉がでてくると、 いまいち分からない気がしてしまいます。

ですが、結局のところ 「呼び出し元関数、またはメソッド (親)」 の引数になる 「呼び出される関数 (子)」 のことをコールバックと言っているのに過ぎないということです。

※ ただし、このページのサンプルでは実践的なコールバックの使い方は取り上げていませんのでご了承ください。

目次に戻る

サンプルコードと実行結果

ここでは、コーリング関数とコールバック関数を使って関数の入れ子処理をシンプルに再現しています。 具体的な処理については、このセクションの後半とコード説明を参照してください。

サンプルコード: HTML
<body>
	<output id="idOutput">innerText</output>
	<script>...</script>
</body>
  • 02: output (識別子に idOutput を持つ要素です。 この要素のテキストに関数とコールバック関数の処理結果を表示します。)
サンプルコード: script
<script>
	function Calling_X10 ( Callback_Value ){
		return Callback_Value * 10;
	}
	function Callback_X100 ( First_Value ){
		return First_Value * 100;
	}
	let elmOutput = document.getElementById("idOutput");
	elmOutput.innerText = Calling_X10( Callback_X100( 5 ) );
</script>
  • 02-04: function Calling_X10 (Callback_Value){関数の処理} (コールバック関数の呼び出し元の関数です。この関数の引数にはコールバック関数の処理結果の値が渡されます。)
  • 05-07: function Callback_X100 (First_Value){関数の処理} (コールバック関数です。この関数は呼び出し元の関数により呼び出され、処理結果を呼び出し元関数の引数として渡します。この関数は 09行目で呼び出されており、引数には (5) を指定しています。)
  • 08: elmOutput (識別子に idOutput を持つ要素を参照するための変数です。)
  • 09: elmOutput.innerText = 関数の呼び出し(idOutput の要素のテキストに Calling_X10 関数の処理結果を代入します。)
実行結果:
innerText

以下に処理の具体的な流れと説明を書き出しておきます。

関数は、関数を呼び出す前に作成 (定義) しておく必要がありますので、02:行~07行までで関数を定義しています。

Calling_X10 ( Callback_Value ) とは
呼び出し元の関数です。これは「親の関数」と位置づけることができるものです。 引数の (Callback_Value) の部分にはコールバック関数のリターン値が渡されます。

Callback_X100 ( First_Value ) とは
呼び出される関数です。つまり、これがコールバック関数です。 呼び出し元から呼び出され、処理した結果を呼び出し元の引数に渡す役割があります。

Calling_X10( Callback_X100( 5 ) )
09:行目が関数を呼び出しているコードです。 これが関数を入れ子にしているコードですが、 呼び出し元の関数を実行するには引数としてコールバック関数の結果が必要ですので、先に Callback_X100(5) の関数が実行されます。 コールバックの引数には 5 という値を指定しています。この 5 という値は Callback_X100関数の引数である First_Value に渡されます。 結果として、Callback_X100(5) は {5 * 100} を処理して、 500 をリターンします。

この 500 は Calling_X10 (Callback_Value) の Callback_Value の部分に渡されるので結果として、 Calling_X10(500) は {500 * 10} を処理して、 5000をリターンします。

目次に戻る

javascriptにおける関数の記述方法

javascript には関数のコードの記述方法が 2つ用意されています。 次の2つのコードを見て下さい。 これは関数の処理としては、まったく同じ処理をしています。

これは DocW という Function オブジェクトを生成しているシンプルなコードですが、 引数である str とその周辺のコードの違いに着目してください。

近年ではコールバック関数を使う場合に、コールバックの意味を込めて上のコードのように 「 => 」 を使った書き方が多くなりました。 この 「 => 」 も 「 function 」 と同じ意味ですので、プログラマーの視点から見ると視認性が良く理解しやすいからだと思います。 しかし、この記述方法は Microsoft IE (Internet Explorer) では処理されません。

IE を使うユーザーが訪問する可能性がある限り、私は後者のコード記述を行う方が無難なように感じます。

<script>
	let DocW = str => document.write(str);
	DocW("Hello World");
</script>
<script>
	let DocW = function(str){document.write(str)};
	DocW("Hello World");
</script>

目次に戻る

コールバックのまとめ

このページで説明しているコールバック関数は、実はコールバックとしては、あまり実用的ではありません。 ただ、コールバックの意味としては大筋で見て取れると思います。

ただし、経験豊かなプログラマーが意識するコールバックの在り方とは違うでしょう。 実用的なコールバックとは呼び出し元関数 (親) の引数を、呼び出される側の関数 (子) の引数に渡し、子供に処理をさせることが本来の在り方だと思います。

つまり親関数から子供の関数に引数を丸投げして処理をさせ、戻り値を得るといった考え方です。 しかし、これを説明する、もしくは理解するとなると難解になる可能性がありますので、ここでは詳細的なサンプルは掲載しません。

高度な使い方は、次第に理解できるようになるものと思って、 とりあえず、コールバック関数とは 「 関数に渡される関数 」 ということだけ覚えておいてください。

目次に戻る