for文内で関数定義し、定義した関数を実行した時の挙動で困ったのでメモ
for文内で関数定義
for文内で関数を定義して、それをfor文の外で呼び出して実行しようとしました。
sample1.js
var functions = []
for (var i = 0; i < 3; i++) {
functions.push(function(){
console.log(i);
});
}
functions[0]();
functions[1]();
functions[2]();
0,1,2と表示されることを期待していましたが結果は以下のように。
3
3
3
あれ?と思ったのですが、少し考えるとループを回している変数iは定義したfunctionの外のスコープにあることに気がつきました。
即時関数でスコープを作る
0,1,2と表示させるために、定義したfunctionでスコープを作りスコープ内で定義した変数を参照させるようにします。そこで即時関数を用います。即時関数は今あるスコープとは別に新たなスコープを作成するので、即時関数を使用して以下のように書き換えました。
sample2.js
var functions = [];
for (var i = 0; i < 3; i++) {
//即時関数
(function () {
var x = i;
functions.push(function () {
console.log(x);
});
})();
}
functions[0]();
functions[1]();
functions[2]();
すると期待通りの結果に。
0
1
2
即時関数は、定義+実行の目的以外に、今回の場合やスコープ汚染を防ぐために利用するそうです。
letを使う
ES6で追加された宣言letを使ってfor文を回します。letによってfor文のブロックでスコープを構築します。
sample3.js
var functions = [];
for (let i = 0; i < 3; i++) {
functions.push(function(){
console.log(i);
});
}
functions[0]();
functions[1]();
functions[2]();
すると期待通りに。
0
1
2