
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); });});
- メリット:
indexやthisを一切気にする必要がありません。コードが非常に読みやすくなります。
どちらがいい?
今の主流は 案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 と書こうが)、中に入ってくるものは同じ「クリックの情報」です。
現場での「お作法」
何でもいいとは言いつつも、エンジニアの世界には「暗黙の了解」があります。
e: 一番よく使われます(Eventの頭文字)。短いので楽。event: 丁寧な書き方。初心者にも分かりやすい。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つだけ渡してあげよう」
あなたが引数の名前を 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() という、「ブラウザの元々の動き(リンクへの移動など)をキャンセルする」 超重要なテクニックについて解説しましょうか?
作品

コメントを残す