もう二度と「JavaScriptは呼び出し方によってthisが変わるという奇怪な言語なんですよ~(ドヤ顔)」とかするでないぞ??
この記事を書いた動機
Qiitaに定期的に(本当に定期的に!)この手の記事が投稿されるから。
ではさっそくfunctionをこの世から葬り始めましょう!
アロー関数とクラスの導入
この二つがES2015で追加されたのは既知の事実です。そして、この二つの登場でfunctionが表舞台に出てくることがほぼなくなりました。
JavaScriptにおいてfunctionの呼び出し方は次の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が強制されているわけではありません。
ここも消し去れませんでした・・・ぐぬぬ
まとめ
というわけで、
- (後から追加する)メソッドとしてのfunction
- apply、callされるためのfunction
という特殊なケース以外なら、functionはアロー関数とクラス構文で置き換えられることがわかりました。もうthisはfunctionが呼び出された時にほぼ自明に決まる時代となりました。thisが変わることに神経質になる時代は終わりました。thisが変わることに神経質になる時代は終わりました。(大事なことなので)
もうJavaScriptのthisは4種類とか書くなよ!絶対だぞ!