メソッドとして関数を呼んだ場合の this の値

今日は、うっかり忘れがちな「メソッド内の this が何を示すか」を復習するついでに、脳内ダンプしてみます。

C++ の this には、

  • 「this(ポインタ)は メソッドの親オブジェクトを示す」
  • 「メソッド内では、 this->hoge() と hoge() は同じ意味になる。thisは省略できる(例外あり)(テンプレート内の名前解決とか)」
  • 「関数の中では this は未定義」

と、明確なルールがありますが、JavaScript の this は呼び出し方により中身が変化する BuzzWord です。

obj1.obj2.fn() の fn の中で this は何になるか

window.x = "global";
window.fn = function() {
    alert(this === window);
    alert(this.x);
};

window.lv1 = {
    x:  "lv1",
    fn: function() {
        alert(this === lv1);
        alert(this.x);
    },

    lv2: {
        x: "lv2",
        fn: function () {
            alert(this === lv1.lv2);
            alert(this.x);
        }
    }
};
実行するとこうなる
window.fn();         // true, "global"
window.lv1.fn();     // true, "lv1"
window.lv1.lv2.fn(); // true, "lv2

JavaScript的には

  • ドット は 「オブジェクトの要素にアクセスする演算子
  • () は「要素を関数として呼び出す演算子
  • オブジェクトに紐づいている関数はメソッドと呼ばれる
    • 関数とメソッドは扱いが異なる
  • 「メソッドを呼び出すときに使用したオブジェクトが、メソッドの本体の中で this キーワードの値になる」(サイ本 8.4 メソッドとしての関数)
    • メソッド呼び出しは、メソッドが所属するオブジェクト(thisが表すもの)を処理するための構文
      • メソッド呼び出しでは、this が暗黙のうちに設定され、渡される。

長いですね。

つまり

obj1.obj2.fn() の中の this は obj1.obj2 です。

obj1.obj2.fn() は、「obj1 の要素の obj2 の fn という要素を、obj1.obj2 を this としたメソッドとして実行する」 という意味になります。

これらを踏まえると

↓は上記の例と同じ結果になります(無駄に長くて遅いけど)

window.fn.call(window);                 // == window.fn()
window.lv1.fn.call(window.lv1);         // == window.lv1.fn();
window.lv1.lv2.fn.call(window.lv1.lv2); // == window.lv1.lv2.fn();

Function.call や Function.apply に undefined や null を渡すと、トップレベルオブジェクト(ブラウザ上なら window) が渡されるため、

↓も同じ結果になります。

window.fn.call(); // == window.fn()