Javascript ES5 などで this がおかしい時に確認すること
Javascript(ES5 など古いやつ) の this は呼び出し元次第で中身が変化するという、大変扱いづらい仕様をしている。そのせいで、なぜか TypeError が発生し、調べてみると this がなぜか別のオブジェクト(window)を指していたりする。勘弁してほしい。何度ハマったことか。
というわけで、「おかしい時に確認すること」と題して、まとめておく。次ハマったら、ここを見に来ること。
- 1: new してるか確かめろ
- 2: jQuery 等でメソッドチェーンでコールバック関数書いてると this は見えないから外から見ろ
- 3: xxxx.func を this._func = xxxx.func みたいに持たせるのはやめて
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(); ... } ...