「イベントリスナー」を説明できますか

# はじめに
趣旨は表題のとおりです
「イベントリスナー」説明できますか？

更に「イベントハンドラー」2つの違いと関係を説明できますか？

現在のGUIを持つプログラムの多くはイベント制御を主軸に設計されています。
ですのでボタンや画像を使った凝ったアプリを作りたいという場合には「イベント〇〇」を知る必要があります。

筆者は今でこそ使い分けられているものの、プログラミング入門当時これらの区別がつくまでに数ヶ月を要しました。
数ヶ月の成果をアウトプット練習を兼ねて書き留めたものがコレです。

この記事は、厳密な部分を抜きにした各用語と関係の概要理解が目的です。
枝葉末節の正確性についてはご容赦ください。

本記事は可能な限りプログラミング未経験の方にも分かるように、極力コードを使わない説明を心がけて執筆しました

一部やむを得ない部分はJavascriptによるDOM操作をベースに解説している箇所があるので簡単なJavascriptを書いたことがあると理解が早いと思います。

クリックに対してメッセージを出力するボタンを作ったことがある、位で十分です。


# 用語

## イベント(Event)
日常生活で言う「イベント」は平時に無い特別な催しを指すことが一般的です。

プログラムにおける「イベント」は、**プログラム動作中に起きるあらゆる出来事**の総称です。

- ボタンがクリックされた
- 文字が入力された
- サーバーから応答が返った
- プログラム起動から一定時間が経った

等々、起きる事全てがイベントです。

## イベントハンドラ(Event Handler)
**イベントの発生に応じて実行するように紐付けられた処理**です。
名前の「Handle」は取っ手や持ち手でなく、「扱う」「担う」「応対する」の意味です。

例えばこの記事の「いいね」ボタンを押すとハートマークが緑色に変化しますよね。

この「緑に変化させる処理」が、ボタンのクリックというイベントに対して紐付けられたイベントハンドラです。

# イベントターゲット(Event Target)

イベントリスナーの説明の前に、イベントターゲットを知っておきましょう。

:::note
イベントターゲットは主にJavascriptにおける名称です。
言語やライブラリによって名前が異なることがありますが、同等の機能は殆どの言語に存在します。
:::

**ある要素Aに対してイベントが起きることを想定して、イベントを検知できるように実装された要素A** をイベントターゲットと呼びます。

例えば、ボタンは当然クリックというイベントを受け付ける想定があります。
文字入力欄は、キー入力というイベントを受け付けて、欄に入力された文字をリアルタイムで表示します。

このようにイベントを受け付ける想定がされているボタン要素や入力欄要素は後述のイベントリスナーを登録することでそのイベントを検知し紐づいた動作を行うことができるようになります。

言い換えれば、イベントリスナーを登録する手段を持つものをイベントターゲットということもできます。


# イベントリスナー(Event Listener)
**イベントターゲットがイベントを検知して制御できる機能を実現する仕組み**がイベントリスナーです。

イベントリスナーは発生するイベントの種類と対応するハンドラのセットを携えてイベントターゲットに抱え込まれ、ターゲットにイベントが発生するとハンドラを実行します。

ターゲットは複数のリスナーを持つことができ、様々なイベントに対して反応することができます。

ターゲットが受付窓口であればリスナーは対応マニュアルを持った担当者といったところです。

名称の「Listener」ワードチョイスについてですが、筆者は由来を明記した文献を見たことがありません。
耳を澄ましてイベントの発生通知が聞こえてくるのを期待して耳を澄ますといったニュアンスでしょうか。

## イベントディスパッチャー
イベントに耳を澄ますのがイベントリスナーであれば、**イベントを発信して聞かせる**のがイベントディスパッチャーです。

イベントディスパッチャーを直接操作する機会は、リスナーやハンドラに比べれば比較的少ないかもしれません。

しかしこれ無しではリスナーもハンドラも機能しないため重要な概念であることは言うまでも無いでしょう。

多くの場合においてディスパッチャーの実体は呼び出し可能な関数やメソッドで、引数に発信するイベントを受け付けます。

ディスパッチャーは自分でイベントを作成して扱いたいときに使うことになります。
Javascriptからしばしば利用するWebAPIや、多くのGUIフレームワークにはよく使われるイベントが予め定義されています。
例えば「クリックとはこういう動作である」と自分で定義しなくても
```js
eventTarget.addEventListener("click", (event) => {handler(event)} )
```
が動くのはそれが理由です。
こういった既成イベントでない独自イベントを作り任意のタイミングで発生させたいという場合にディスパッチャーを呼び出します。

### 閑話休題: Javascriptにおけるlistenerとhandler

これまで例に出してきたJavascriptですが、イベント処理のコードが易しいため採用しているものの特に名称についてはいくつかややこしいポイントがあります。
筆者が理解に苦しんだ部分を整理しておきます。

#### Listener
:::note
この章ではaddEventListenerの第二引数を英字表記listener、上で説明したイベントリスナーはカタカナ表記リスナーで書き分けます。
:::
直前の例に上げた`addEventListener(type, listener)`はイベントターゲットのメソッドで、名前の通りターゲットにリスナーを登録します。
第二引数に関数や`handleEvent()`メソッドを持つオブジェクトを指定し、これが第一引数で指定するイベントに対応するハンドラになるのですが、**ハンドラに相当するはずの第二引数の引数名が`listener`です**。

Javascriptではイベントの扱いについて「listenerをハンドラとして呼び出す」ではなく **「イベントの発生通知をlistenerに聞かせる」** という考え方のようです。

視点をlistener側に持てば確かにlistenerはイベント発生を期待して耳を澄ましているリスナーと言えます。
**引数のlistenerは俯瞰的立場では（イベントターゲットに登録されるリスナーの）ハンドラである**と補正すると良いかもしれません。

#### handler
Javascriptを書いた経験のある方は
```js
eventTarget.onClick = handler()
```
という書き方でもイベントに対する処理を記述できることを知っていると思います。
**この`onClick`はハンドラと呼ばれます**。

筆者は最初
「ハンドラは`handler()`の方じゃないの？　だって呼び出される処理は`handler()`でしょう？」
と思ったものです。

結論を言うと、`onClick`はハンドラで正解です。

**一部のイベントについては、イベント発生時に実行される関数が`on〇〇`の名前で定義されています**。
既定ではこれらは`null`に設定されており、関数に代入する形で本命のハンドラである`handler()`を設定します。
**イベントが発生すると、ハンドラとして`on〇〇`が呼び出されます**。そこに本命ハンドラが代入されていれば、それは`on〇〇`の名において処理を実行するわけです。

## イベントループ
**イベント発生の有無を判定してハンドラを呼び出せるように待機するループプログラム**です。
下図のようにイベントの監視は一般にループを使います
```plantuml
start
:イベントリスナー登録;
 repeat
if(登録されたイベントが発生したか) then(No)
 :待機;
else(Yes)
 split
   :イベントA;
:ハンドラA;
split again
   :イベントB;
:ハンドラB;
split again
   :イベントC;
:ハンドラC;
end split
endif
:最初に戻る;
```
中でも起動から終了まで動き続けプログラム全体のイベントを統括制御する大きなループを**メインループ**と呼びます。

# 各々の関係まとめ
1. プログラム実行時に起きる色々な出来事を**イベント**として定義することで柔軟な動作を実現できる
1. **イベントハンドラ**にはイベントが起きたとき実行したい処理を実装する
1. **イベントリスナー**を使ってイベントとイベントハンドラを紐付ける
1. **イベントディスパッチャー**を使って自由にイベントを発生させることができる
1. イベントを受け付けるリスナーはイベントが起きる対象である**イベントターゲット**に登録する


# あとがき
イベントに対応して動く仕組みの実装方法は色々あります。

今回JavascriptのDOMをベースに説明しましたが、言語やフレームワーク、ライブラリによっては上記の説明は当てはまらないことがあります。

しかし1つの例で概念を理解すれば、他の環境においても「Javascriptでいう〇〇にあたる機能」とおおよその見当をつけられることで調べやすくなったり、理解しやすくなるのでは、と筆者は思います。


イベントを扱えるようになると、作れるものがぐんと増えます。
Webサイト、スマホアプリ、ゲーム、Bot。リッチな動きを実装できるようになるとプログラミングは一段と楽しくなるでしょう。

皆さんの「作りたい」を実現できる一助になることを願っています。

ありがとうございました。