2016年5月15日日曜日

クロージャの変数捕捉タイミングが変わってる!(JS編)

みなさん、こんにちは。また間が空いてしまいました。はざまです。
今回は久しぶりにJSの話題をしようと思います。

今日、昔書いたJSアプリの修正を行っていたのですが、以下のようなコードを書いてみて愕然としました。

jsdo.itの説明文にも書いた通り、コメント内の記法でChromeやSafariで評価を行うと、これまたコメント内のように、関数の実行順とリンクした結果が表示されたんですね。一昔前の挙動は、jsdo.it内のテストコードのように、順繰りにカウントアップされるというものだったんですが、いつからこのような挙動になったんでしょうか。
そもそも、jsdo.it内だと、ループ内にクロージャを定義できなくなっていること、Chrome、Safariともに同じ挙動だったことから、おそらく標準規格が変わったんだと思いますけど、今はそこまで追う余裕もないので、推測だけ記載しておきます。きっと、パフォーマンスの観点から、ループ内に無名関数を定義できなくした上に、既存のコードを吟味して下方互換性を保たなくても大丈夫という判断がなされたんでしょうけど、私個人としては、かなり衝撃的な仕様変更でした。……って、めちゃくちゃ個人的な理由ですね。
ワークアラウンドとしては、例にも示した通り、Function.prototype.bindを使うことです。クロージャを保持するための一時変数が必要になったり、thisにbindするわけでなければ、第1引数にnullを指定しなきゃいけなかったり、クロージャをさっと書けていた時代に比べると、ちょっと不格好なのは否めませんが、ループ最適化でパフォーマンスが向上するのなら、我慢しようといったところでしょうか。

6/7 追記: TypeScriptのマニュアルを読んでいて見つけた別のワークアラウンド。即時実行関数を挟むパターン。例に出している構文も酷似してるし、MS内に私のクローンがいるんでしょうか……

ではでは、またそのうちお会いしましょう^^/

0 件のコメント:

コメントを投稿

なにか意見や感想、質問などがあれば、ご自由にお書きください。