2012年05月08日

JavaScriptの変数のスコープ

JavaScriptの変数のスコープについて、あまりわかってない私がはまった罠。
下記のコードで、alertで表示されるのは何でしょうか?



失敗例
window.onload = function() {
//ファンクションの配列
var funcList = [];

//0〜2をalertで表示するファンクションを作る。
for (var i = 0; i < 3; i++) {
funcList[i] = function() {
alert(i);
}
}

//0番目のファンクションを実行すると・・・?
funcList[0]();
}




「3」が表示されます。私の意図では「0」が表示されてほしかったのですが・・・。


詳しい説明は他人様のサイトにお任せするとして、すごーくざっくり説明してみます。内側のファンクション(7行目)は変数iを使っています。内側のファンクションを実行するとき(12行目)、JavaScriptのエンジンは「変数iはなんぞや?」と出所を探します。内側のファンクションの中には変数iの定義はないので、さらにその外側を探しに行きます。スコープチェーンってやつですね。めでたく外側のファンクションで見つかったので、その値を使います。カウンターが回りきってるので変数iは「3」になると。


ざっくり説明はこの辺にして、回避策を出します。



回避策
window.onload = function() {
var funcList = [];

for (var i = 0; i < 3; i++) {
//functionで囲む。
(function(n){
funcList[n] = function() {
alert(n);
}
})(i);
}

//ちゃんと「0」が表示される!
funcList[0]();
}




「(function(){・・・})();」を日本語にすると、「匿名関数を定義して即実行」って感じでしょうか。上記の例では、こいつに引数として変数iを渡しています。こうすることによってスコープチェーンが切れるんですね。変数iと匿名関数の引数nはまったく別の参照ってことです。ちなみに、引数の名前を「n」から「i」に変えても正しく動きます。



全部「i」にしてみた
window.onload = function() {
var funcList = [];

for (var i = 0; i < 3; i++) {
//引数の名前を「i」にしてみた。
(function(i){
funcList[i] = function() {
alert(i);
}
})(i);
}

//ちゃんと「0」が表示される!
funcList[0]();
}




同じものを表すのだから同じ名前がいいですね。わかりやすくするために名前を変えるのもいいと思います。お好みでどうぞ。




ラベル:javascript
posted by ぺるたご at 00:07| Comment(1) | TrackBack(0) | 日記 | このブログの読者になる | 更新情報をチェックする
この記事へのコメント
そんなことをしなくてもletを使えばいいだけでは…
Posted by ななし at 2012年12月27日 21:07
コメントを書く
お名前:

メールアドレス:

ホームページアドレス:

コメント:

認証コード: [必須入力]


※画像の中の文字を半角で入力してください。

この記事へのトラックバック
×

この広告は1年以上新しい記事の投稿がないブログに表示されております。