JavaScriptのaddEventListenerで関数に引数をわたす方法(bind)

2021年2月28日JavaScript

JavaScriptのaddEventListenerで関数に引数をわたす方法を紹介します。
bind()メソッドを使った方法です。
なぜ失敗するのかを把握することも大事なので、失敗例も合わせて記載します。

addEventListenerの使い方は、次の記事を参考にしてみてください。


bind()メソッドの使い方は、次の記事を参考にしてみてください。

addEventListenerで関数に引数を渡せていない失敗例

順を追って説明するために、まずは失敗例から紹介します。



//関数
const handleHover = function(e, opacity) {

    if(e.target.classList.contains('nav__link')) {
      const link = e.target; 

      const siblings = link.closest('.nav').querySelectorAll('.nav__link');
      const logo = link.closest('.nav').querySelector('img');
  
      siblings.forEach(el => {
        if(el !== link) el.style.opacity = opacity;
      });
      logo.style.opacity = opacity;
    }

//動かない。関数は渡せているものの、引数を渡せていません。なので動きません。
   nav.addEventListener('mouseover', handleHover);
}

関数にe,opacityという引数を渡したいとします。
addEventListenerの第二引数に、上のように関数を渡します。
これは、動きません。
関数は渡せているものの、引数を渡せていません。なので動きません。

addEventListenerで関数ではなく値を渡してしまっている失敗例



//関数
const handleHover = function(e, opacity) {

    if(e.target.classList.contains('nav__link')) {
      const link = e.target; 

      const siblings = link.closest('.nav').querySelectorAll('.nav__link');
      const logo = link.closest('.nav').querySelector('img');
  
      siblings.forEach(el => {
        if(el !== link) el.style.opacity = opacity;
      });
      logo.style.opacity = opacity;
    }

//動かない。関数ではなく実行された値を渡してしまっている。
   nav.addEventListener('mouseover', handleHover(e, 0.5));
}

上の関数handleHover部分は同じです。
addEventListenerの第二引数には、関数そのもの(=handleHover)」を指定しなければいけません。
handleHover()をわたすと、「その関数の実行結果の値」を渡していることになり、関数を渡していません。
つまり、handleHover()やhandleHover(opacity)としても値であって、関数ではないので動きません。

addEventListenerで関数を渡せている成功例(コードが冗長になる)


//関数
const handleHover = function(e, opacity) {

    if(e.target.classList.contains('nav__link')) {

      console.log(this, e.currentTarget);//thisはundefined, e.currentTargetはnavを指定しているので、navタグになります。
      const link = e.target;
  
      const siblings = link.closest('.nav').querySelectorAll('.nav__link');
      const logo = link.closest('.nav').querySelector('img');
  
      siblings.forEach(el => {
        if(el !== link) el.style.opacity = opacity;
      });
      logo.style.opacity = opacity;
    }
}

//動く例1 
nav.addEventListener('mouseover', function(e) {
  handleHover(e, 0.5);
});
nav.addEventListener('mouseout', function(e) {
  handleHover(e, 1);
});

これはコールバック関数を渡しているので動きます。
ただし、複数あるとコードが冗長になるのと、解除(アンバインド)する事が出来ません。

addEventListenerのthis

const button = document.querySelector("button");

const red = function () {
  // button.style.color = "green"; //buttonではなくthisでOK
  this.style.color = "green";
};

button.addEventListener("click", red);

こちらの例では、buttonにaddEventListener()が登録されているため、buttonがthisの参照先となります。
そのため、コールバック関数でthisを使用すると、buttonを指します。

addEventListenerでbindを使って引数を渡す成功例

上の方法は、2つも同じコードを書いています。
このような場合、bindでthisを決めるといいです。



//関数
const handleHover = function(e) {//opacityが不要になります。

    if(e.target.classList.contains('nav__link')) {
      console.log(this);//0.5 / 1が表示される

      const link = e.target;
  
       const siblings = link.closest('.nav').querySelectorAll('.nav__link');
      const logo = link.closest('.nav').querySelector('img');
  
      siblings.forEach(el => {
        if(el !== link) el.style.opacity = this; //ここはopacityではなく、thisでOKになります。
      });
      logo.style.opacity = this; //ここはopacityではなく、thisでOKになります。
    }
}
//動く例2
nav.addEventListener('mouseover', handleHover.bind(0.5));
nav.addEventListener('mouseout', handleHover.bind(1));//bindは新しい関数を返します。

bind()は新しい関数を返します。そしての関数は0.5という値が設定されています。
関数内でコンソールにthisを表示すると0.5が渡せていることがわかります。
thisは通常currentTargetとイコール。しかし、いまのcurrentTargetはnavタグになるため、それをbind()で手動で指定します。
つまり、opacityはthisで表せるので、opacityも不要になります。

今回は一つの引数のみですが、さらに複数の引数を渡す必要がある場合は、配列やオブジェクトを入れて渡します。