質問編集履歴

1 最終的なコードの追加

lazex

lazex score 420

2018/04/15 12:08  投稿

共通リスナに参照をもたせる良い方法
タイトルだけだと何がいいたいかよくわからないですが、
`addEventListener` でリスナを作るときに `removeEventListener` で解除するためにどこかに参照を保持する必要があります。
リスナ自体は同じ処理なのでひとつですが内部で別のインスタンスを参照させたいです。
しかし、リスナは event しか引数をとりません。
自分で 「event を受け取って、 event と インスタンスを渡してリスナを実行する」 関数を作っても結局それを `addEventListener` に登録する以上その参照を保持する必要があります。
その参照をオブジェクトのプロパティには可能な限りしたくないです。
理由は公開したくないのと、リスナをインスタンスごとに持たせるのがムダに思うからです(可能なら共通のものにしたい)。
公開しないというものは共通の WeakMap を 1 つ用意してインスタンスに対する任意のデータをもたせるようにして、そこに実際に登録したリスナを入れることにしました。
ただ、これはこれで手間な方法に思います。
もっと簡単な方法がありそうに思うのですが、思いつきません。
何か良いアイデアがありましたら、教えてください。
---
# 具体例
コードがないと分かりづらいと思うので一例を載せます。
```js
class X{
   setListener(){
       window.addEventListener("click", listener, false)
   }
   removeListener(){
       window.removeEventListener("click", listener, false)
   }
}
function listener(eve){
   x.prop = eve.target
}
export { X }
```
`X` のインスタンスそれぞれがリスナを追加します。
このままだと、 `listener` 内部で `x` が見つからないとエラーがでます。
`x` は各 `X` のインスタンスを指します。
`x` で参照できるように `x` を受け取る作りにします。
```js
setListener(){
   const self = this
   this.listener = function(eve){
       listener.call(this, eve, self)
   }
   window.addEventListener("click", this.listener, false)
}
```
```js
function listener(eve, x){ // 引数が追加
   x.prop = eve.target
}
```
ここで `this.listener` の関数がそれぞれのインスタンスに対して作らないといけないのと、それを `X` のインスタンスに保持しないといけないのが嫌な部分です。
`X` のインスタンスに持たさないためにこうしました。
```js
setListener(){
   const self = this
   const listener = function(eve){
   const listener_wrapper = function(eve){
       listener.call(this, eve, self)
   }
   wmap.set(this, listener)
   window.addEventListener("click", listener, false)
   wmap.set(this, listener_wrapper)
   window.addEventListener("click", listener_wrapper, false)
}
```
```js
const wmap = new WeakMap()
```
たかだかリスナにオブジェクト参照をもたせたいだけでこんなに変更するのはなにか違う気がします。
書いてて無理そうな気もしてきたのですが、なにか方法がありそうにも思います。
書いてて無理そうな気もしてきたのですが、なにか方法がありそうにも思います。
# 追記
最終的にどうなっている状態かがわかりづらいため全体のコードを追記します。
また、上記コードで `listener` が重複していたので修正しました。
```js
const wmap = new WeakMap()
class X {
   setListener(){
       const self = this
       const listener_wrapper = function(eve){
           listener.call(this, eve, self)
       }
       wmap.set(this, listener_wrapper)
       window.addEventListener("click", listener_wrapper, false)
   }
   removeListener(){
       window.removeEventListener("click", wmap.get(this), false)
   }
}
function listener(eve, x){
   x.prop = eve.target
   console.log(x)
}
export { X }
```
補足すると EsModules のモジュールのため、 wmap はこのファイル外には公開されていません。
  • JavaScript

    23250 questions

    JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

思考するエンジニアのためのQ&Aサイト「teratail」について詳しく知る