スコープ

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) に関連付けられている。
スコープ連鎖はオブジェクトのリストで、Identifier の評価の際に検索され
る。制御が実行コンテキストに入るとき、コード型毎にオブジェクト集合の初
期値を伴うスコープ連鎖が生成され、組み込まれる。実行コンテキスト内にお
ける実行の間、実行コンテキストのスコープ連鎖は with 文(12.10) と catch
クローズ(12.14) によってのみ影響を及ぼされる。

http://www2u.biglobe.ne.jp/~oz-07ams/prog/ecma262r3/10_Execution_Contexts.html

ということで何が言いたかったかというと,関数スコープならこういう風に書けてもいいじゃんと思ったけど,

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

*1:let は興味津々の方向でlispっぽく