FC2ブログ

スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

for文で関数を作る

javascriptでは関数を動的に作成できます。
ただfor文で関数を動的に作成したときに、少しわかりにくい問題にはまってしまいました。

var array = [];
for(var i=0;i<2;i++)
array.push(function(){return i;});
for(var obj in array)
alert(array[obj]());

このようなコードを書くと、alertで出力されるメッセージは2回とも"2"となります。
原因はiの変数が呼び出されるタイミングがarray[obj]()としたときであるためです。

C言語を触ったことのある人だとすぐに分かるかと思いますが、おそらくポインタ的な感じかと思います。
"return i;"のコードで書かれているのはあくまで変数iの呼び出しであって、関数を定義した時のiの数値ではないのです。つまり、array[obj]()が実行されるときの変数iの値は2であって、0でも1でもないのです。

さて、解決策はどうしようと思った時に結構悩んでしまいました。
変数iではなく、その関数を定義した時のiの数値を使いたいわけですが、そのような操作を行う関数やメソッド、プロパティが思い浮かびませんでした。

最終的に思いついた解決策は以下のとおりです。

var array = [];
for(var i=0;i<2;i++){
var j=i;
array.push(function(){return j;});
}
for(var obj in array)
alert(array[obj]());

変数jに代入しただけです。
何をしているかというと、for文の中で繰り返し変数jを再定義しています。繰り返す度に変数jには新しい箱が用意されているわけですが、前の箱はどこに行くかというとどこからも参照できなくなります。正確にいうと、定義した関数内で参照が残っているので、消えずに残っています。

この辺りまで来るとJavaのガーベージコレクションを思い出すわけですが、本来どこからも参照がなくなるとそのメモリ空間は削除されます。しかしながら、どこかで参照が残っていると仮に元の変数が消えたとしても削除されません。

もっと言うと、ある変数Aを定義すると、メモリアドレスxxxxに箱が用意されます。もう一度変数Aを定義すると、箱が被らないように今度はメモリアドレスyyyyに箱が用意されます。本来この時点でメモリアドレスxxxxはどこからも参照がなくなるので、メモリアドレスxxxxに用意された箱は削除され、別の箱が必要になったときに使える状態になります。しかしながら、メモリアドレスxxxxを指した変数Bを何らかの方法で用意されてしまうと、メモリアドレスxxxxは参照が残っているので削除されなくなります。というよりも削除されると変数Bは正しい値を提供できなくなってしまいます。

またfor文の中で定義された変数はfor文の中だけで使えるローカル変数(だった気が。。。)なので、for文の外では参照できなくなります。つまり変数jはfor文の外では"定義されていない"のですが、array[obj]()したときに変数jは参照可能です。この時の変数jは関数が定義された時の変数j(正確にはメモリアドレス)を指しているので、参照可能なのです。

という感じで少し頭が痛くなるような解決策で何とか動かすことができました。

コメントの投稿

管理者にだけ表示を許可する

プロフィール

sin

ニックネーム:sin

趣味でプログラムの作成などをしています。

Google+1
最新記事
カテゴリ
検索フォーム
リンク
最新コメント
RSSリンクの表示
ブロとも申請フォーム

この人とブロともになる

上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。