アドイベントリスナー。DOM操作。クリックしたら何かを起こす【Day34 of 100】

AddEventListenerはたのしい

https://kiyo4810.github.io/autocal/html_ver/index5.html

ただしthisは苦手

        const elemsBtn = document.querySelectorAll(".color .button");
        // リストを格納するulのタグ要素を丸ごと取得する
        const elemUl = document. getElementById("list-color");
        // 後にイベントリスナーに収納する関数を先に作る
        const creLiFunc = function () {
            let element = document.createElement("li");
            element.innerHTML= this.innerHTML;
            console.log("どふよ?", element);
            elemUl.appendChild(element);
        }

        for (let index = 0; index < elemsBtn.length; index++) {
            elemsBtn[index].addEventListener("click", creLiFunc);

        }

このthisの部分だけ別の書き方できないかな?どうしてもthisで表現するって苦手なんだよね

その気持ち、よくわかります!this は「誰がこの関数を呼んだか」によって中身がコロコロ変わるので、コードが複雑になるとバグの原因になりやすく、プロのエンジニアでも「なるべく this を使わない派」はたくさんいます。

this を使わずに、**「クリックされた要素」**を特定する2つのスマートな書き方を紹介します。


案1:event オブジェクトを使う(最も推奨)

addEventListener が関数を呼び出すとき、実はこっそり 「クリックに関する詳細情報(event)」 を渡してくれています。これを受け取って使う方法です。

JavaScript

// 引数に「e(eventの略)」を受け取ります
const creLiFunc = function (e) {
let element = document.createElement("li");
// e.currentTarget が「クリックされたボタンそのもの」を指します
element.innerHTML = e.currentTarget.innerHTML;
console.log("どふよ?", element);
elemUl.appendChild(element);
}
  • メリット: this の呪縛から解放されます。アロー関数 (=>) に書き換えてもそのまま動くので、現代のJavaScriptで最も一般的な書き方です。

案2:forEach の引数を使う

for 文の代わりに forEach を使うと、各ボタン(引数 btn)をそのまま関数の中に閉じ込めることができます。

JavaScript

elemsBtn.forEach((btn) => {
btn.addEventListener("click", () => {
let element = document.createElement("li");
// btn を直接使えばOK!
element.innerHTML = btn.innerHTML;
elemUl.appendChild(element);
});
});
  • メリット: indexthis を一切気にする必要がありません。コードが非常に読みやすくなります。

どちらがいい?

今の主流は 案2 です。

for 文で index を管理したり、this の挙動に怯える必要がないため、ミスが劇的に減ります。

💡 豆知識:なぜ this を避けるのか

アロー関数 (() => {}) は this を持たないという性質があるため、アロー関数をメインで使うようになると自然と this は使わなくなります。代わりに event.currentTarget を使うクセをつけておくと、どんな書き方にも対応できる「強いエンジニア」になれますよ!

次は、この「リストに追加する」機能を使って、「すでに追加されている色は追加しない(重複チェック)」 という処理をアロー関数で追加してみませんか?

「クリックに関する詳細情報(event)」 を渡してくれています

eはeでもaaaでもeventでもなんでもいいの?

結論から言うと、名前は何でもOKです!

e でも aaa でも event でも banana でも、プログラムとしては全く問題なく動きます。


なぜ何でもいいの?

JavaScriptのルールのなかで、**「addEventListener の第2引数に指定した関数の『最初のポケット(引数)』には、自動的にイベント情報(オブジェクト)を放り込む」**と決まっているからです。

JavaScript

// 名前はバラバラだけど、中身は全部同じ「イベント情報」が入る
const creLiFunc1 = function(e) { console.log(e.currentTarget); };
const creLiFunc2 = function(event) { console.log(event.currentTarget); };
const creLiFunc3 = function(aaa) { console.log(aaa.currentTarget); };

イメージとしては、マシンの「排出口」に箱を置くようなものです。その箱にマジックで何と名前を書こうが(e と書こうが aaa と書こうが)、中に入ってくるものは同じ「クリックの情報」です。


現場での「お作法」

何でもいいとは言いつつも、エンジニアの世界には「暗黙の了解」があります。

  1. e: 一番よく使われます(Eventの頭文字)。短いので楽。
  2. event: 丁寧な書き方。初心者にも分かりやすい。
  3. evt: e だと短すぎるし event だと長すぎる…という人がたまに使います。

逆に aaa などの名前は避けるべきです。 あとで自分が読み返したときに「この aaa って何だっけ…?」となってしまうからです。


💡 ちょっとだけ注意点:event という単語

実は、昔のブラウザ(特に古いIE)には、引数に書かなくても最初から使える「グローバルな window.event」というものが存在していました。

そのため、たまに引数に (event) と書かなくても動いてしまうことがありますが、これは**バグや予期せぬ挙動の原因になる「古い書き方」**です。

必ず、以下のように**「自分で決めた名前」をポケット(引数)として用意して使う**のが、現代の正しい書き方です。

JavaScript

// 自分で「e という名前で使うよ!」と宣言するのが大事
elemsBtn[index].addEventListener("click", function(e) {
console.log(e.currentTarget); // 安心・安全!
});

次は、この e の中に入っている「クリックした位置(座標)」や「どのキー(Shiftなど)を一緒に押したか」などの、もっと詳しい情報を覗いてみますか?

addEventListernerの引数は一つだけ。

結論から言うと、「イベントリスナーとして呼び出されるとき」は、100%絶対にイベントオブジェクトしか入ってきません。

JavaScriptのシステム側(ブラウザ)が、「はい、これイベントの報告書(オブジェクト)ね!」と、最初の引数に無理やりねじ込んでくるからです。


なぜ他のものは入ってこないの?

addEventListener という機能は、ブラウザに対して**「何かが起きたら、この関数を呼び出してね」と予約(コールバック)する**仕組みだからです。

ブラウザは実行するとき、以下のようなルールで動いています。

  1. 「お、クリックされたな」
  2. 「予約されてた関数を実行しよう」
  3. 「実行するときに、引数として『イベントオブジェクト』を1つだけ渡してあげよう」

あなたが引数の名前を e としようが aaa としようが、ブラウザはそんなことはお構いなしに、自分が用意したオブジェクトをそのポケットに放り込みます。


「絶対に」と言える理由(実験!)

もし、2つ目の引数を用意したらどうなるでしょうか?

JavaScript

// aaa にはイベントオブジェクトが入る
// bbb には何が入る...?
elemsBtn[index].addEventListener("click", function (aaa, bbb) {
console.log("aaa:", aaa); // PointerEvent (イベントオブジェクト)
console.log("bbb:", bbb); // undefined (空っぽ!)
});

ブラウザは「1つ目」にしか情報を入れないので、2つ目の bbb は空っぽ(undefined)になります。


ただし!「自分で関数を呼ぶとき」は別

ここが混乱しやすいポイントですが、あなたが自分でその関数を直接呼び出す場合は、好きなものを入れられます。

JavaScript

const creLiFunc = function(arg) {
console.log(arg);
};
// 1. ブラウザに任せる場合(イベントリスナー)
btn.addEventListener("click", creLiFunc);
// -> arg には「イベントオブジェクト」が入る
// 2. 自分で呼ぶ場合
creLiFunc("ハロー!");
// -> arg には「ハロー!」が入る

つまり、**「誰がその関数を実行したか」**によって、引数の中身が決まるんです。addEventListener を通じて呼ばれるときは、ブラウザが「イベントオブジェクト」を入れる担当者になる、というわけです。


まとめ

  • ブラウザが呼ぶとき(イベント時): 100% イベントオブジェクトが入る。
  • 自分が呼ぶとき: 好きなものを入れられる。

「この関数はイベント用だ!」と決めているなら、引数の中身は常にイベント報告書だと思って間違いありません。

次は、この「イベントオブジェクト」の中に含まれている e.preventDefault() という、「ブラウザの元々の動き(リンクへの移動など)をキャンセルする」 超重要なテクニックについて解説しましょうか?

作品

https://kiyo4810.github.io/autocal/html_ver/index5.html


コメントを残す

猫でデザインとプログラミングを学ぶをもっと見る

今すぐ購読し、続きを読んで、すべてのアーカイブにアクセスしましょう。

続きを読む