スコープ
Perl だとブロックスコープ{...} なんだけど,JavaScript だと実行コンテキストスコープ(function(){...})()だよ.と
my $func; { my $i = 0; # 変数$iのスコープ $func = sub { print($i); }; } # ここまで
var func; (function() { var i = 0; // 変数iのスコープ func = function() { alert(i); }; })(); // ここまで
えーと,解説というか根拠的なもの.
Under Translation of ECMA-262 3rd Edition(ECMAScript Language Specification)とか見てみた.
10 実行コンテキスト (Execution Contexts)
制御が ECMAScript の実行可能コードに転送される時に、制御は 実行コンテ
キスト に入る。アクティブな実行コンテキストは論理的にスタックを形成す
る。この論理的スタック上の実行コンテキストの頂点が、実行される実行コン
テキストである。10.1.3 変数の実体化 (Variable Instantiation)
各実行コンテキストは 変数オブジェクト (variable object) に結び付けられ
http://www2u.biglobe.ne.jp/~oz-07ams/prog/ecma262r3/10_Execution_Contexts.html
ている。ソーステキスト内に宣言された変数と関数は変数オブジェクトのプロ
パティに追加される。関数コードについては、パラメータが変数オブジェクト
のプロパティに追加される。
つまり何を言いたいかというと,関数を定義された時点では変数が生成されておらず,実行時に初めて(実行コンテキストに移ってから)変数オブジェクト(つまりスコープ)が生成されるらしい.
あと,ググってて到達したnanto さんとこ見て気付いたんだけど,with とかでも同じようなことができるみたい.あとlet とか
10.1.4 スコープ連鎖と識別子の解決 (Scope Chain and Identifier
Resolution)各実行コンテキストは スコープ連鎖 (scope chain) に関連付けられている。
http://www2u.biglobe.ne.jp/~oz-07ams/prog/ecma262r3/10_Execution_Contexts.html
スコープ連鎖はオブジェクトのリストで、Identifier の評価の際に検索され
る。制御が実行コンテキストに入るとき、コード型毎にオブジェクト集合の初
期値を伴うスコープ連鎖が生成され、組み込まれる。実行コンテキスト内にお
ける実行の間、実行コンテキストのスコープ連鎖は with 文(12.10) と catch
クローズ(12.14) によってのみ影響を及ぼされる。
ということで何が言いたかったかというと,関数スコープならこういう風に書けてもいいじゃんと思ったけど,
var divs = document.getElementById('target').getElementsByTagName('div'); for (var i = 0; i < divs.length; i += 1) { divs[i].addEventListener('click', function() { var j = i; alert(i); }, false); }
自分はスコープがわかってなくて,関数宣言と実行コンテキストをごっちゃにしていた.
わかってみるとこういう風にも書けるじゃんと思った次第.
var divs = document.getElementById('target').getElementsByTagName('div'); for (var i = 0; i < divs.length; i += 1) { divs[i].addEventListener('click', (function(i) { return function() { alert(i); }; })(i), false); }
with は,覚えたくないので,忘れていいですか?*1