thisの遅延束縛 - JavaScriptの個人的なメモ (その3)

このメモについて

他の言語とJavaScriptの違いに関する個人的なメモですので、誤りがあるかもしれません。見つけたらご指摘ください。

前回のメモ - JavaScriptの多重継承とオーバライド - JavaScriptの個人的なメモ (その2)

http://d.hatena.ne.jp/dhrname/20121004
今回はthisを解説します。

this

JavaScriptにおいて、thisは参照しているオブジェクト自身のこととは限りません。
というのは、関数が呼び出される前には、thisに何が入っているのか不明です。関数が呼び出されるときに、その値を初めて決定します。
ためしに、nプロパティに数値の12を入れてみましょう。

  var f = function(){
         this.n = 12;
      },
      obj = {
              hoge : f
      };
  /*関数呼び出しパターン ( this = グローバルオブジェクト )*/
  f();
  window.n;  /* 12 */

  /*apply (call) 呼び出しパターン (this = 第1引数)*/
  var s = {};
  f.apply(s);
  f.call(s);
  s.n;        /* 12 */

  /*メソッド呼び出しパターン ( this = その場で呼び出したオブジェクト)*/
  obj.hoge();
  obj.n;      /* 12 */

  /*即時関数 ( this = グローバルオブジェクト )*/
  (function(){
    this;    /* グローバルオブジェクト */
  })();

  /*コンストラクタ呼び出しパターン (returnを指定していなければ、this = 返り値)*/
  s = new f();
  s.n;       /* 12 */


  /*メソッドの参照引渡し つまり、メソッド呼び出しパターン*/
  s.hoge = obj.hoge;
  s.n = 0;
  s.hoge();  /* this = s, this != obj */
  s.n;       /* 12 */

  s = obj.hoge;
  s();
  window.n;  /* 12 だが、注意点として、IE8以前だけは、obj.n が12となる。IE9では修正*/

 this;       /* グローバルオブジェクト */

なお、このコードで使われているwindowオブジェクトが必ずしもグローバルオブジェクトとは限りません。これはブラウザの独自実装であることにご注意ください。
上のコードのとおり、メソッドの参照引渡しで問題が起こるのはthisのためです。
thisの性質を使えば、こんなこともできます。

document.id = function (id) {
  return this.getElementById(id);
};
document.id("s"); /* メソッド呼び出しパターンなので、this = document */

結論

  • thisは、値が流動的なので注意
  • 関数呼び出しパターンはthisがグローバルオブジェクトになるので、特に注意

続き

プロトタイプ - JavaScriptの個人的なメモ (その4)

http://d.hatena.ne.jp/dhrname/20121101