【JavaScript】 コールバック関数とイベントリスナーの違い
更新日:2021/11/10
JavaScriptを学んでいるとコールバックとイベントリスナーという言葉を耳にします。
どちらも関数で、メソッドの引数として用いられているので違いが判らず、戸惑ってしまいます。
そこで両者の違いを調べてみました。
コールバック関数とは
処理の汎用性を高める仕組み
プログラミング言語の多くは処理の汎用性を高めるために用いられるコールバック(callback)という仕組みがあります。
コールバック関数は、この仕組みで利用される関数です。
言語に組み込まれている関数やメソッド、モジュールやAPIなどは、呼び出し側のコードで処理内容を改変することができません。
しかし処理の一部を呼び出し側で作成して、それを引数として受け取って内部で実行することで柔軟な処理ができるようになります。
この呼び出し側で作成した関数が、コールバック関数です。
例えば、JavaScriptのmapメソッドはコールバックの仕組みで動作しています。
const array = [ 1 , 2 , 3 ].map( e => e * 3 );
console.log( array ); // [ 3 , 6 , 9 ]
e => e * 3 がコールバック関数です。
mapメソッドは、配列の各要素をコールバック関数に渡して、その戻り値で新しい配列を作成します。
新しい値をmapメソッドで決めずに、コールバック関数に丸投げすることで汎用性を高めているわけです。
通知という意味合いもある
コールバック関数には、なんらかの条件を満たしたときに、そのことを呼び出し側に通知するという意味合いもあります。
例えば、次のようなコードです。
setTimeout( ()=>{
//なんらかの処理
} ,5000)
setTimeoutは、二番目の引数で受け取った時間が経過したら、一番目の引数(コールバック関数)を実行する関数です。
言い方を変えると、『時間が経過したことをコールバック関数で通知した』ということです。
JavaScriptのPromiseは、ほぼコールバックで動作していると言えます。
const promise = new Promise( (resolve, reject) => { /* 何らかの処理 */ } );
promise.then( ()=>{ /* 何らかの処理 */ } )
.catch( ()=>{ /* 何らかの処理 */ } );
最初の行は、汎用性を高めるためのコールバックです。
thenはPromiseが解決通知を受け取るコールバックを、catchは拒否通知を受け取るコールバックを登録しています。
イベントリスナーとは
コールバック関数の一種
イベントリスナーは、コールバック関数の一種です。
JavaScriptなどのイベントドリブンなプログラム言語は、ボタンが押されたり外部との通信が終了するなどのイベントが発生するまで待機しています。
そしてイベントが発生すると、あらかじめプログラムコードで登録されていた関数が呼び出されます。
この関数はイベントリスナーやイベントハンドラと呼ばれます。
イベントリスナーは関数やメソッドの引数として登録されます。
そのためコールバック関数でもあります。
■イベントリスナーやイベントハンドラの違い
イベントハンドラ:一つのイベントに対して一つの関数を割り当てて呼び出す
イベントリスナー:一つのイベントに対して複数の関数を割り当てて順番に呼び出す
明確な基準はないけれど、上のように認識している人が多い
JavaScriptのイベントリスナー
JavaScriptの場合、イベントリスナーはEventオブジェクトから派生したオブジェクトを引数として受け取る関数を指すことが多いです。
JavaScriptでの派生は、プロトタイプチェーンを指します。
■参考:【JavaScript】 プロトタイプとは?prototypeプロパティはプロトタイプではない件について
例えば、DOM要素をクリックすると登録されたコールバック関数が呼び出されます。
呼び出された関数は引数としてMouseEventオブジェクトのインスタンスを受け取ります。
これはEventオブジェクトから派生しています。
document.getElementById("id").addEventListener( "click",e=>{
console.log( e instanceof MouseEvent ); // true
console.log( e instanceof UIEvent ); // true
console.log( e instanceof Event ); // true
});
Event ⇒ UIEvent ⇒ MouseEvent の順番で派生
派生しているかどうかは、instanceofで確認できます。
■参考:【JavaScript】 instanceof演算子とは?何を比較しているのか?
setTimeoutの時間経過は、クリックと同様にイベントループで処理されます。
しかしコールバック関数に引数が渡されません。
setTimeout( e=>{
console.log( e ); // undefined
},5000);
そのため、setTimeoutのコールバック関数はイベントリスナーと呼ばれません。
JavaScriptのイベントハンドラ
イベントによっては、イベントハンドラを登録できるものがあります。
登録方法はイベントによって異なりますが、専用のプロパティを用意しているものが多いです。
例えばクリックイベントは、onclickプロパティでイベントハンドラを登録できます。
イベントハンドラも、イベントリスナーと同じ引数を受け取ります。
document.getElementById("id").onclick = e=>{
console.log( e instanceof MouseEvent ); // true
console.log( e instanceof UIEvent ); // true
console.log( e instanceof Event ); // true
});
イベントハンドラとして登録できる関数は一つだけです。
再度登録すると、上書きされます。
ただし、イベントハンドラとイベントリスナーは個別に機能します。
addEventListenerで登録したものは影響しません。
更新日:2021/11/10
関連記事
スポンサーリンク
記事の内容について
こんにちはけーちゃんです。
説明するのって難しいですね。
「なんか言ってることおかしくない?」
たぶん、こんなご意見あると思います。
裏付けを取りながら記事を作成していますが、僕の勘違いだったり、そもそも情報源の内容が間違えていたりで、正確でないことが多いと思います。
そんなときは、ご意見もらえたら嬉しいです。
掲載コードについては事前に動作確認をしていますが、貼り付け後に体裁を整えるなどをした結果動作しないものになっていることがあります。
生暖かい視線でスルーするか、ご指摘ください。
ご意見、ご指摘はこちら。
https://note.affi-sapo-sv.com/info.php
このサイトは、リンクフリーです。大歓迎です。