【TypeScript】「this」についてC#、Javaから来る人はハマりやすい!?
TypeScriptは、JavaScriptに型定義とクラスベースでコーディングができるようにしたもの。
C#やJavaのクラスになれていると取っつきやすいな、感じました。
フリーのVirtual Studio Codeを使えば、コーディング中の型定義のエラーや、インテリセンスも動いて便利です。
しかし気を付けないといけないのは、最終的にはコンパイルしてJavaScriptになる、と言うところ。
JavaScriptの時点でクラスベースに浸っている人にはthisの扱いに気をつけないと行けない訳ですが、まず解説はこの辺りで。
TypeScript上はクラスとして書ける分、thisをC#やJavaのように自身のインスタンスを示すthisのつもりで使ってしまいそうですが、 このクラスもあくまでTypeScriptのコーディング上でクラスなだけで、このthisもJavaScriptの仕様に基づきます。
クラスとして書いているので、通常はnewしたインスタンスのメソットでアクセスすればthisは自身のインスタンスを示すthisになる訳ですが、そのメソッドを別のインスタンスのメソッドして設定したりある要素のイベントハンドラに割り当てたりすると、thisは呼び出し元としたインスタンスになってしまいます。
また、メソッド内でfunctionの匿名メソッドなどを書いた場合は、thisはグローバルオブジェクト(strictモードで変わる)になってしまいます。
これがラムダ式(アロー関数)だと扱いが変わるのがさらにややこしいですね。。この場合は、定義時点のthisで固定される(メソッド内のthisはそのスコープの外と同じ)のでどちらかと言えばこちらの方がC#やJavaのthisの感覚に近く、またラムダ式の方が使い慣れているかと思うので基本的にはラムダ式で書いていくのが良さそうですね。
ちなみにTypeScriptはES5に基づきますが、JavaScriptでのラムダ式はES6からなのでラムダ式はTypeScriptとして機能拡張しています。
なので、コンパイルするとJavaScriptのラムダ式でのthisの仕様になるように呼び出し前のthisを別変数に受けて、その変数で置き換えられたJSファイルになっています。
これが、
class Sample {
public test() {
let func1 = () => {
alert(this.title);
}
func1();
let func2 = function() {
alert(this.title);
}
func2();
}
}
こんな感じにコンパイルされます。
function e(){
this.hoge=void 0
}
return e.prototype.test=function(){
var e=this;
var t=function(){
alert(e.hoge)
};
t();
var i=function(){
alert(this.hoge)
};
i()
}
ためしにletを使ってみましたが、letもES6なのでTypeScriptではエラーにならずJSファイルではvarに変わってますね。
クラスベースに慣れているからと言って、JavaScriptの理解が無いままTypeScriptを使うとハマりやすいかな、と言うところです。
なぜなら実際自分も間違えて少しハマってしまいましたので。。