var a = new Array();
function f(){
for(var i = 0;i < 10;i++){
a[i] = function(){
window.alert(i);
};
}
}
f();
a[0]();
a[9]();
window.alert(i);
が実行されるのはf()が終了(forループが終了、i=10。)したあとだからだと思います。
f(); ※forを10までまわしてf()が終わり。 ※このときi=10
↓
a[0]();でwindow.alert(i); ※このときi=10
↓
a[9]();でwindow.alert(i); ※このときi=10
このソースにおいて
<script language="javascript"> var a = new Array(); function f(){ //① i が10になったら終了 for(var i = 0;i < 10;i++){ a[i] = function(){ window.alert(i); }; } // 地点B ( 変数i の値は 10 ) } f(); // f()が実行されたため、地点Bを通る // 「i」という名前の変数が他に無いので、この地点で // 「i」という名前で参照される値は「10」になる a[0](); a[9](); </script>
■解説
a[0]~a[9]にalertを使った関数を定義するループ①において、
このやり方ですと、埋め込まれているのは、
その時の「i」の値(固定値)ではな「「i」という変数をリアルタイムに参照せよ」
というコード
であるため、処理の内容は、呼び出されたそのときリアルタイムに
「i」という名前の変数を探し出し、
値をとってきてalertで表示する」
という処理を定義することになります。
そのため、「定義をしているときに、何回目のループで、
「i」の値はいくつだったか」
という情報は反映されません。
あくまで、
「リアルタイムに「i」を探し出せ」という
命令を組み込んだ関数ということになっています。
そのため、ループ後に
a[0]を呼んでもa[9]を呼んでも、
「リアルタイムに「i」を探し出す」
という全く同じ処理をしているだけなので、
for文の条件(i <10)から、
ループが終わったとき、「i」の値は「10」になっており、
2つとも「10」が表示されます。
■異なるものを表示させるには~
ループ回転中の異なるループ変数「i」の値を反映した処理をさせるには、
次の方法を使います。
<script language="javascript"> var a = new Array(); function f(){ // i が10になったら終了 for(var i = 0;i < 10;i++){ a[i] =function() { // 式を文字列化すれば、iの値を反映できる。 eval("window.alert(" + i + ");") } } } f(); a[0](); a[9](); </script>
このように、ループ変数「i」ごとに処理を変化させる部分は、
文字列式で処理を定義し、
eval()で呼び出すようにすることで、
異なる処理をさせることができます。
文字列は、命令コードのようにリアルタイムに探し出すのではなく、
定義された時点で固定されるからです。
こちらのWikiにも書きます。
JavaScript/ループを使った関数定義のテクニック - ジャックズラボ jack's Lab
やっぱりiが評価されるタイミングというのが肝になるんですかね。
eval()を使った解決法は、デモンストレーション的ですね。
提示されたコードでは、配列aのメンバはすべて同じ関数への参照です。なので、同じ挙動しかしません。
以下のようにすればできます。
var a = new Array(); function f(){ function make(j){ return function(){ window.alert(j); }; } for(var i = 0; i < 10; i++){ a[i] = make(i); } } f(); a[0](); a[9]();
各関数を別に生成するため、関数makeを作成しています。
親関数内の子関数(クロージャ)は、親関数の実行ごとに生成されるという性質があります。
参考:http://d.hatena.ne.jp/keyword/%A5%AF%A5%ED%A1%BC%A5%B8%A5%E3
参考になりますでしょうか。
なるほど、こんな風に書けるんですね。「クロージャ」がキーワードなのかな。
そういうことですよね。
無名関数の扱いとかの辺りのもうすこしつっこんだ解説やURLを教えていただけるとありがたいです。
あと、逆に「このプログラムを0と9が表示されるように作り変えるとしたらどうしたらよいか」も募集してみますのでよろしくお願いします。