なぜHTMLコメントにはイベントリスナーが付与できるのか
HTMLのコメントにはaddEventListener
やremoveEventListener
などのイベント関連の処理が実装されています。
DOMの構造に詳しい方であれば、このような仕様になっている理由が分かる方も多いかと思われます。
今回はHTMLのコメントの仕様を通じてDOMについての理解を深めるための記事を書きます。
前提条件
この記事は下記の内容を前提として記載しています。
- JavaScriptの基礎的な構文を理解している
- 基本的なHTML要素を把握している
- オブジェクト指向プログラミングについての基礎的な理解がある
最後の「オブジェクト指向プログラミングについての基礎的な理解がある」については推奨ですが必須ではありません。
確認手順
まずは本当にコメントにイベントリスナーが実装されているかを確認します。
確認のためnew Comment()
でHTMLのコメントを作成し、typeof
演算子でaddEventListener
が関数として存在するのかを確認[1]しています。
const comment = new Comment('foo');
// => <!--foo-->
console.log(typeof comment.addEventListener);
// => "function"
確認の結果typeof
演算子によって"function"
が返却されaddEventListener
という関数が登録されていることが確認できました。
DOMの構造についての解説
実際にメソッドが存在することは確認できたので、次になぜこのような仕組みになっているのかを解説していきます。
なぜコメントにイベントリスナーが存在するのか
答えを先に出すと、コメントにもaddEventListener
/removeEventListener
が存在する理由としては、Comment
インターフェイスがEventTarget
インターフェイスを継承しているからです。
上記の理由がどういう意味なのかを実際にブラウザのコンソールなどを使って確認してみます。
実際にインターフェイスの継承構造をたどってみる
まずは継承構造の確認から始めようと思います、ChromeなどのコンソールではDOMのプロパティが確認できるためそれを利用して確認を行います。
先程と同じようにnew Comment()
でコメントを作成してみてその中身をブラウザのコンソールで確認してみましょう。
const comment = new Comment('foo');
console.log([comment]);
次にコンソール上でコメントオブジェクトを配列から展開して、[[Prototype]]
という項目を何度も開いていくと下記のような順番で開いていくと思います。
Comment
CharacterData
Node
EventTarget
Object
この作業はDOMの継承関係を遡っていく作業だと思ってください。
この内Object
はJavaScript全体の環境まで飛び出しているのでDOMの世界としてはEventTarget
が最上位のインターフェースとなります。
HTMLButtonElement
(button要素)の場合を例とすると下記の図のような継承が行われています。
HTMLButtonElementのDOMインターフェイス継承関係を表した図
解説のためにbutton要素を出してしまいましたが、コメントと比較した場合どちらもNode
インターフェイスまでは共通しています。
そのためbutton要素もコメントもNode
インターフェイスが持っているメソッドやプロパティを利用することができることが分かります。
もしbutton要素についても継承の確認を行いたい場合は先程のコードからnew Comment('foo')
の部分をdocument.createElement('button')
に変更することで確認可能です。
このようにDOM上の様々な要素は対応するインターフェイスを継承することである程度の分類が行われています。
そのため、EventTarget
を継承しているコメントもbutton要素も同じようにイベントリスナーを設定することができます。
EventTargetインターフェイスとはなにか
今までの説明や名前からも想像できるようにEventTarget
はイベントを受け取るためのメソッドを定義したインターフェースです。
そのため、イベントを受け取ることができる要素やオブジェクトはEventTarget
インターフェースを継承しています。
図にも記載があったようにaddEventListener
やremoveEventListener
などはこのインターフェイスで定義されています。
ブラウザで利用できるAPIにはHTMLの要素以外にも(Window
など)イベントを受け取ることができるオブジェクトが存在するためこのインターフェースが最上位に位置しています。
まとめ
以上の確認からHTMLのコメントにもaddEventListener
が存在する理由として、コメントがEventTarget
インターフェイスを継承している構造が理解できたかと思われます。
このようにDOMの構造を理解することで、要素が持つプロパティやメソッドが要素固有のものなのか、それともすべての要素が持っているものなのかなどが理解しやすくなります。
またTypeScriptを利用している場合はinstanceof
演算子を利用した型ガードなどがより正確に記述できるようになります。
普段何気なく利用しているHTMLやDOMですが、少し深掘りしてみるとまた見え方が変わってきてDOMの扱いもより正確に記述できるようになります。
MDNのDOMの紹介ページなどではより詳しい解説などもありますので、もし興味が湧いたらぜひ読んでみてください。
参考資料
-
Google Chrome 115 及び Firefox 116 にて確認 ↩︎
Discussion