ECMAScript6でthisを束縛する方法について

ECMAScript6でthisを束縛する方法について検証した際のメモ

まずダメな例として、以下は画面クリックの際に呼ばれる clickFunc から this.calledFunc() を呼び出すことはできません。クリックに反応したelementがthisになるため、この場合はリスナーが設定されたdocumentがthisになりthis.calledFunc()を呼び出すことはできません。

class Application {
  constructor(){
    this.init();
  }

  init() {
    document.addEventListener('click', this.clickFunc, false);
  }

  clickFunc(event) {
    this.calledFunc();
  }

  calledFunc() {
    alert("called");
  }
}

const app = new Application();

bindを使う

よく使われる方法としてはbindを使ってthisを束縛する方法があります。今回の場合は以下のようになります。これなら簡単に思った通りになります。

class Application {
  constructor(){
    this.init();
  }

  init() {
    document.addEventListener('click', this.clickFunc.bind(this), false);
  }

  clickFunc(event) {
    this.calledFunc();
  }

  calledFunc() {
    alert("called");
  }
}

const app = new Application();

Arrow関数を使う

ECMAScript6から導入されたArrow関数を使うとthisは関数定義時に通常の関数と同じように決まるので、以下でも呼び出すことができます。

class Application {
  constructor(){
    this.init();
  }

  init() {
    document.addEventListener('click', (event) => {this.clickFunc}, false);
  }

  clickFunc(event) {
    this.calledFunc();
  }

  calledFunc() {
    alert("called");
  }
}

const app = new Application();

関数の実装を他のクラスに分ける場合

Applicationクラスに関数が増えすぎたなどでclickFunc の実装を他のファイルに分けたい場合, thisのさす先が変わるのでそのままではApplicationに割り当てられた関数を利用することができません。その場合は以下のように束縛対象にObjectを渡すことで想定した動きにできます。

test-func.js

export function clickFuncGen(app) {
  const func = (event) => {
    app.calledFunc();
  }
  return func;
}

index.js

import * as T from './test-func';

class Application {
  constructor(){
    this.init();
  }

  init() {
    this.clickFunc = T.clickFuncGen(this);
    document.addEventListener('click', this.clickFunc, false);
  }

  calledFunc() {
    alert("called");
  }
}

const app = new Application();