リハビリに手頃な問題だったので。

これ、実は「Java開発者のためのAjax実践開発入門」でも紹介されている書き方。

for 文と無名関数のイディオム - IT戦記
というわけで、これをすべて解決するのが
for (var i = 0, len = list.length; i < len; i++) (function(node, i) {
    var text = node.textContent; 
    node.onclick = function() { alert(text) };
})(list[i], i)
なのだ。

ただし、コメント欄に残された問題が残る。

自分でも検証してみた。

n = :

これ、デフォルトでは100万回にしてあるけど、IEで実行する場合は一桁少ない10万が推奨。

Scopeless

var result = 0;
for (var i = 0; i < n; i++){
  result = i;
}

Closure as a block

var result = 0;
for (var i = 0; i < n; i++) (function(a){
  result = a;
})(i);

with()

var result = 0;
for (var i = 0; i < n; i++) {
    with({a:i}) {
        result = a;
    }
}

どのブラウザーで実行しても、function()しない方が速いのだけど、IEの場合、笑っちゃうほど遅くなってしまう。

で、少し工夫してみる。

Closure as a block, predefined

var result = 0;
for (var i = 0, block = function(a){ result = a }; i < n; i++) block(i);

Closure as an iterator

var result = 0;
(function(block){
    for (var i = 0; i < n; i++) block(i);
})(function(a){
    result = a 
});

いずれの場合も倍以上高速にはなった。IEだとそれでもまだ我慢できないほど遅いけど。

とはいえ、amachangの例ではスコープはどうしても必要になる。

以上をふまえると、

for (var i = 0, len = list.length; i < len; i++) (function(node, i) {
    var text = node.textContent; 
    node.onclick = function() { alert(text) };
})(list[i], i)

var block = function(node){
    var text = node.textContent; 
    node.onclick = function() { alert(text) };
};
for (var i = 0, len = list.length; i < len; i++) block(list[i]);

と書くのが現状でのベストプラクティスかと思われ。別の言い方をすると、なるべくループの中ではclosureを生成しない方がよい。

Dan the JavaScripter