`that = this` について思ったこと
Posted: Updated:
thatに思いを馳せる
JavaScriptにおいて that = this
とか self = this
なパターンを頻繁に使うと、作業者の理性が保証されない場合に下記に示す2点の問題が起こりう得ると思っている。
「あー、どうなのかなー、うーん」と思いながら書いてみる。
1.メソッド分割が適切におこなわれない雰囲気
ちょっと極端かも知れないが、Backboneっぽいコードを例にしてみる。
initialize: function() { var that = this; this.listenTo(this.entity, 'success', function() { var bar = that.foo(); that.$el.find('.qux').text(bar); // long. // long.. // logic... }); this.entity.execute(); }
いわゆるthat = this
をするって、こういうことだと思う。練度が低い or 理性を失ったメンバーがこれを扱うのはマズい空気がある。that
にまつわるロジックが長々と拡張されたり、色々な変数を2つのスコープでいっぱい使いたいからモリモリ作ってまたがせ始めたりとか危うい。
initialize: function() { this.listenTo(this.entity, 'success', _.bind(this.onSuccess, this)); this.entity.execute(); }, onSuccess: function() { var bar = that.foo(); this.$el.find('.qux').text(bar); // long. // long.. // logic... }
このように分割しておいたほうがよいと思うのです。個々に_.bind()
するのが面倒であれば、_.bindAll()
だってあるし。
2. スコープ広がりすぎでリファレンスカウントこわい
いわゆるレキシカルスコープ的な特性の話になるのだけど
initialize: function() { var that = this; this.listenTo(this.entity, 'success', function() { var bar = that.foo(); that.$el.find('.qux').text(bar); // (ry }); this.entity.execute(); }
たとえばこれが
initialize: function() { var that = this, bigObject = this.getFatObject(); // ** BIG! SO BIG!! ** this.listenTo(this.entity, 'success', function() { var bar = that.foo(); that.$el.find('.qux').text(bar); // (ry }); this.entity.execute(); }
とかbigObject
を呼んで
initialize: function() { var that = this, bigObject = this.getFatObject(); // ** NOT COLLECTED BY GC ** this.listenTo(this.entity, 'success', function() { var bar = that.foo(); that.$el.find('.qux').text(bar); // (ry }); $('#outer-element').on('click', function() { var hoge = that.getHoge(); $(this).val(bigObject.prop); // (ry }); this.entity.execute(); }
とか迂闊なものを加えられると、DOMイベントのリスナとして登録されたクロージャが、bigObject
のリファレンスカウントを抱えたまま失踪する珍事になりかねないと怖がっている。それこそdelegateEvents()
を使えという話だが。
listenTo()
も同様に、オブジェクトを使い終わったらremove()
なりstopListening()
なりしないと同じような話になるだろう。
あ・・・
全体的に、コードレビュー徹底しやがれという話なのですが、やはりあまり良い習慣とは思えないのでした。とはいえ、実は自分自身bind
の利用歴がさほど長くないので、bind
の副作用とかアンチパターンも思いつかず。どうなのかな〜と。
ここまで書いて、[].map()
とか_.find()
みたいなときに渡すthat = this
もあるよなーと気づいた。まあでも似たような話とは思うし、そもそもcontext
ないしthisObject
を渡せるな彼らは。