JavaScriptの with文で prototype.jsの bindを省けたが
そのなかに bind methodの実装がある。 prototype.jsから持ってきた物らしいんだけど気持ち悪い:
Function.prototype.bind = function() { var __method = this, args = $A(arguments), object = args.shift(); return function() { return __method.apply(object, args.concat($A(arguments))); } }JavaScriptの thisは呼び出されるときまでなんになるか決まらないので、それを bindして closureのようにしてしまうためのものだ。
例えば、今の thisの barを 100ms 後に変更したくて次のように書いてはいけない:
setTimeout(function() {this.bar = "foo"}, 100);なぜなら function のなかの this 擬変数は、 今の contextの thisとは別物だから。 そのとき thisが何を指してるなんて不定なのだ。shit!
でも、bind methodを使うとそれが解決できる。 下のように書けば、無名関数を実行する時の thisが今の thisを同じ objectであることを保証できる:
setTimeout((function() {this.bar = "foo"}).bind(this), 100);でもそもそも、関数を渡すようなインタフェースになっているというのが OOPLとしてだめじゃん。 ちゃんとしたインタフェースを持った objectを渡すのが OOPLとしての王道だろ。 それを関数を渡すようなことしてるから、schemeの真似したくなって、 でも thisは static scopeに収まらないものだからこんな汚い事してる。
まったく、JavaScriptは腐った言語だ。
でも with文を使ってこれを回避できることに気がついた。
with(this) { setTimeout((function() {bar = "foo"}), 100); }こう書けば、 今ある thisが scope object (って呼び方でいいんだっけ) に なって、barはその member (さらにいえば associationの要素) として 解決されることになる。
static scopeのはずなのに参照すべき environmentを動的に with文で 変えてしまうというかなり変態な技だ。 こんなのができるのは JavaScriptぐらいなのではないか。
ちなみに Safari 3.0 と Firefox 3.0 で動くの確認しました。
まあ、でも geekの多い JavaScript界隈ではこんなのとうに知られているに 違いない。 それでも使われてないのは理由があるのだろうか?
とおもったらwith文は非推奨かもという議論を見つけた。 まあ、スコープを柔軟過ぎるぐらいに変更できる機能だから、 最適化が難しくなるのもむべなるかな。 まあ、とりあえず bind よりは遅くないだろうから使っておこう。
追記: ぐぐったら 既知の技法のようでした。車輪の再発見をしてしまった。
| 固定リンク
この記事へのコメントは終了しました。
コメント