あらかじめ日記

雑記とかブログで使えるスクリプトとかテクニックとか。その他、音楽やアニメ、漫画の話題とかも。

【TypeScript】「this」についてC#、Javaから来る人はハマりやすい!?

TypeScriptは、JavaScriptに型定義とクラスベースでコーディングができるようにしたもの。
C#Javaのクラスになれていると取っつきやすいな、感じました。
フリーのVirtual Studio Codeを使えば、コーディング中の型定義のエラーや、インテリセンスも動いて便利です。

 しかし気を付けないといけないのは、最終的にはコンパイルしてJavaScriptになる、と言うところ。
JavaScriptの時点でクラスベースに浸っている人にはthisの扱いに気をつけないと行けない訳ですが、まず解説はこの辺りで。

developer.mozilla.org

TypeScript上はクラスとして書ける分、thisC#Javaのように自身のインスタンスを示すthisのつもりで使ってしまいそうですが、 このクラスもあくまでTypeScriptのコーディング上でクラスなだけで、このthisJavaScriptの仕様に基づきます。

クラスとして書いているので、通常はnewしたインスタンスのメソットでアクセスすればthisは自身のインスタンスを示すthisになる訳ですが、そのメソッドを別のインスタンスのメソッドして設定したりある要素のイベントハンドラに割り当てたりすると、this呼び出し元としたインスタンスになってしまいます。

また、メソッド内でfunctionの匿名メソッドなどを書いた場合は、thisグローバルオブジェクト(strictモードで変わる)になってしまいます。
これがラムダ式(アロー関数)だと扱いが変わるのがさらにややこしいですね。。この場合は、定義時点のthisで固定される(メソッド内のthisはそのスコープの外と同じ)のでどちらかと言えばこちらの方がC#Javathisの感覚に近く、またラムダ式の方が使い慣れているかと思うので基本的にはラムダ式で書いていくのが良さそうですね。

ちなみにTypeScriptES5に基づきますが、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を使ってみましたが、letES6なのでTypeScriptではエラーにならずJSファイルではvarに変わってますね。

クラスベースに慣れているからと言って、JavaScriptの理解が無いままTypeScriptを使うとハマりやすいかな、と言うところです。
なぜなら実際自分も間違えて少しハマってしまいましたので。。