Javascript ES5 などで this がおかしい時に確認すること

Javascript(ES5 など古いやつ) の this は呼び出し元次第で中身が変化するという、大変扱いづらい仕様をしている。そのせいで、なぜか TypeError が発生し、調べてみると this がなぜか別のオブジェクト(window)を指していたりする。勘弁してほしい。何度ハマったことか。

というわけで、「おかしい時に確認すること」と題して、まとめておく。次ハマったら、ここを見に来ること。

1: new してるか確かめろ

var table_xxx = VIEW_XXXX_SPACE.XXXXTableBuilder(param1, param2);
         //    A
         //    |
         //  new が足りてないぞ!

2: jQuery 等でメソッドチェーンでコールバック関数書いてると this は見えないから外から見ろ

    ...

    var p = ClassXXX.prototype;

    p._onclick = function(){
        var self = this;

        $(some_selector).click(function() {
            var result = this.calc();
                     //  ^^^^
                     // 違うぞ! this は $(some_selector) の中を指してるぞ!
                     // このクラス(もどき)の this が見たいなら
                     // 外で定義してる self を見ろ!
        });
    }

    ...

3: xxxx.func を this._func = xxxx.func みたいに持たせるのはやめて

問題となる書き方:

    ...

    var p = ClassXXX.prototype;

    p.set_update_func = function(f){
        // こんな感じで yyy の update() を保持することを想定.
        //    xxx.set_update_func = yyy.update
        this._func_update = f
    }

    p.process = function(f){
        ...

        // ここでハマる!
        // さっきセットした yyy.update を呼ぶことを想定しているのだろうが、
        // yyy.update() 側で this の中身がおかしくなる!
        // (yyy の中身じゃなくてこの ClassXXX インスタンスの中身になってる。
        this._func_update();

        ...
    }

    ...

じゃあどう書けばいいの?:

→ 関数を保持するのではなくオブジェクトを保持して Duck typing してください。

    ...

    var p = ClassXXX.prototype;

    p.set_yyy_instance = function(yyy){
        this._yyy = yyy
    }

    p.process = function(f){
        ...

        // これなら update() 中の this は yyy インスタンスの中身を指す!
        // 正しく動く!
        //
        // これはいわゆる Duck Typing。
        // 「this._yyy は yyy インスタンスであるはずだ」
        // 「yyy インスタンスであるなら update() を持っているはずだ」
        // 「私は yyy さんの update() をここで呼ぶのが仕事だから、とりあえず呼ぶ」
        // 「実際に _yyy が何を指してるかは知らん。私は呼ぶだけだ」
        // みたいな。
        this._yyy.update();

        ...
    }

    ...