Panda Noir

JavaScript の限界を究めるブログでした。最近は幅広めに書いてます。

functionの呼び出し方でthisが変わる時代は終わったんだよ(ブチギレ)

もう二度と「JavaScriptは呼び出し方によってthisが変わるという奇怪な言語なんですよ~(ドヤ顔)」とかするでないぞ??

この記事を書いた動機

Qiitaに定期的に(本当に定期的に!)この手の記事が投稿されるから。

ではさっそくfunctionをこの世から葬り始めましょう!

アロー関数とクラスの導入

この二つがES2015で追加されたのは既知の事実です。そして、この二つの登場でfunctionが表舞台に出てくることがほぼなくなりました。

JavaScriptにおいてfunctionの呼び出し方は次の4通りあります。

  1. 関数として
  2. メソッドとして
  3. コンストラクタとして
  4. apply、callを使って

それぞれがアロー関数とクラスによってどう置き換わっていくのか見てみましょう。

関数としてのfunction

関数としてのfucntionで(普通の人なら)thisを参照したくなるケースなんてありませんよね。thisはwindowやglobalを指しているだけですから。ならfunctionの代わりにアロー関数に置き換えた方が有用です。一つ外のスコープのthisを参照したいケースはいくらでもありますからね。

// before
function twice(x) {
    // この中でthisを使いたくなるケースが思いつかなかったので普通の関数になってしまいました。
    return x + x;
}
// after
const twice = x => x + x;

はい、functionの呼び出し方が1種類消えました。

メソッドとしてのfunction

2つ目ですね。これもクラス構文に備わっているのでthisがインスタンスを指していることがわかりやすくなりました。はい終了!…といきたいところですが、実は後からメソッドを足すときはfucntionでないといけません。

class Hoge {
    constructor() {
        this.name = 'world';
        this.age = 1.37e+10;
    }
    greeting(name) {
        return `Hello ${name}. I'm ${this.name}`;
    }
}
Hoge.prototype.myage = function() {
    return `I'm ${this.age} years old.`;
};

ここばかりは置き換えられませんでした。ぐぬぬ・・・

コンストラクタとしてのfunction

「ぎょええええ!!クラス構文が導入されているのにfunctionでコンストラクタを作ろうとしているううううううう!!!」

と人間扱いされないこと間違いなしなのでfunctionがコンストラクタとして使われることはありません。クラスをfunctionに書き直すのはトランスパイラの役割です。

apply、callのためのfunction

これが厄介なんですよね。アロー関数はthisをレキシカルに決定するせいでapplyしてもthisが変わってくれません。そのため、applyする対象はfunctionでなければなりません。といってもapplyが呼ばれることもES2015で色々追加されたおかげで減りましたが。

気を付けなければいけないのはjQueryのイベントハンドラですね。あれはthisをapplyを使って指定しているのでfunctionでなければthisを受け取れません。もっとも、ほかの方法でthisに相当するものを取得できるので、functionが強制されているわけではありません。

ここも消し去れませんでした・・・ぐぬぬ

まとめ

というわけで、

  1. (後から追加する)メソッドとしてのfunction
  2. apply、callされるためのfunction

という特殊なケース以外なら、functionはアロー関数とクラス構文で置き換えられることがわかりました。もうthisはfunctionが呼び出された時にほぼ自明に決まる時代となりました。thisが変わることに神経質になる時代は終わりました。thisが変わることに神経質になる時代は終わりました。(大事なことなので)

もうJavaScriptのthisは4種類とか書くなよ!絶対だぞ!