アロー関数の間違った使い方

JSに関する記事をいろいろ見ていたら、アロー関数の理解が違っていることに気づいた。

efcl.info www.tsubasa-note.blog

「ES6ではfunctionをアロー関数で置き換えられるんだね!」という程度の理解だったが、どうもそうではないらしい。
上の記事とかぶってしまうが、忘れないように書いておく。

thisの扱いの違い

まず、アロー関数ではthisの解釈が他の関数宣言とは異なる。
通常の関数宣言では、thisが何を指すのかはコンパイル時ではなく実行時に決まる。
オブジェクト内でメソッドを定義してすぐ呼び出せば、スコープチェーンをたどり、thisはそのメソッドを定義したオブジェクトを指す。
一方で、一度メソッドとして定義した後、別の変数に代入してただの関数として呼び出すと、thisがundefinedになってしまうことがよくある。

これに対して、アロー関数でのthisはコンパイル時に決まるため、どこで呼び出しても常に「アロー関数を定義したコンテキストのthisオブジェクト」を参照するようになる。

アロー関数がうまく使えない場合

例えば、以下の簡単なコードを例にする。

const obj = {
    num: 3,
    sayNum: function() {
        return this.num;
    }
}
console.log(obj.sayNum); // 3

このコードでは、sayNumメソッドはobj.sayNumとして呼び出されているので、thisはobjを指す。そのため、this.numは3になる。

これをアロー関数で書き換えようと思って、やってしまったミスがこちらのコード。

const obj = {
    num: 3,
    sayNum: () => {
        return this.num;
    }
}
console.log(obj.sayNum); // undefined

アロー関数はどう呼び出されたかに関係なく、自身が定義されたコンテキストのthisオブジェクトを参照する。
上のコードは以下と同じと考えるとわかりやすい。

const obj = {}
obj.num = 3,
obj.sayNum = () => {
    return this.num;
}
console.log(obj.sayNum); // undefined

thisはグローバルオブジェクトとなってしまうため、当然obj.sayNumはundefinedとなる。

アロー関数はコールバック関数として使う

よく仕様を読むと、こう書いてあった。

アロー関数は、メソッドでない関数に最適で、コンストラクタとして使うことはできません。

アロー関数の一番の使い所は、メソッドの中でコールバック関数を書くとき。
理解のために、上のコードを強引に書き換えると以下のようになる。

const obj = {
    num: 3,
    sayNum: function() {
     message = () => {
        return this.num;
     }
     return message();
  }
}
console.log(obj.sayNum()); // 3

こう書くとアロー関数はsayNumメソッドの中で定義されているので、thisはsayNumメソッドを指すようになる。

もちろんこの程度のコードであればアロー関数を使う必要は全くない。アロー関数は、メソッドの中でsetTimeoutのような処理を入れたいときなどによく使われている。