PROGRAMMING
javascript
- ページャーを作る(簡易版)
- ページャーを作る 4/4
(クロスブラウザ対策)
(ページャー表示用メソッド)
(ページャーの使い方) - ページャーを作る 3/4
(イベント登録) - ページャーを作る 2/4
(スタイルの設定) - ページャーを作る 1/4
(ページャー用関数を準備)
(各要素を生成) - 自作カレンダーを作る 6/6
(11.~14.各種メソッド)
(15.簡単な使い方) - 自作カレンダーを作る 5/6
(09.祝休日の判定)
(10.閏年の判定) - 自作カレンダーを作る 4/6
(08.イベントの設定) - 自作カレンダーを作る 3/6
(07.スタイルの設定) - 自作カレンダーを作る 2/6
(05.カレンダーのマスのみ作成)
(06.各マスへ年月・日付を埋め込み) - 自作カレンダーを作る 1/6
(01.カレンダーの基を準備)
(02.各月の日数や年月日の区切り文字)
(03.前月・次月指定時の処理)
(04.前月・次月部分の年月を算出) - JS-Image-Resizerを使って画像を高画質で縮小
- ファイルを作成しローカルに保存
- モーダルウィンドウをクラス化
- ストップウォッチを作る
- XMLHttpRequest Lebel2を試してみる
- jQuery:Tableで親・子・兄弟要素を取得
- 文字列をセパレータ文字で分割し配列で返す関数
- forループのカウンタを使用している関数の定義
- クロージャの使いどころ
- JSONPでクロスドメイン
- AjaxでJSON形式のデータを扱う
- jsファイルからjsファイルを呼び出す
- jQuery:モーダルウィンドウを作ってみる
PHP
Java
- IntelliJ.Gradle.JavaFX(6) プラグイン org.beryx.jlink を使ってみる
- IntelliJ.Gradle.JavaFX(5) NSISでインストーラーを作る
- IntelliJ.Gradle.JavaFX(4) exewrapで実行可能jarをexe化する
- IntelliJ.Gradle.JavaFX(3) Jlink でカスタム JRE を作る
- IntelliJ.Gradle.JavaFX(2) すべての依存対象を含んだ Fatjar を作る
- IntelliJ.Gradle.JavaFX(1) アプリケーションを作る
- javaのコンパイルと実行
- イメージを回転する
- Exif情報を簡単に取得できるライブラリ
- 高画質で画像縮小
- JDBCによるデータベース操作
Kotlin
forループのカウンタを使用している関数の定義
forループ内でカウンタ変数を利用し関数を複数定義する場合があります。
その際によく勘違いするのがカウンタ変数の値です。
スコープチェーン形成のタイミングを考えれば、問題なくできそうです。
意図どおりに結果が出ない例
次の例は画面に0から4までの数字を連続で表示しようとしたコードです。
var func = [];
for (var i = 0; i < 5; i++) {
func.push(function(){return i});
}
var result = document.getElementById("result");
var str = "";
for (var j = 0; j < func.length; j++) {
str += func[j]() + " ";
};
result.innerHTML = str; // 「5 5 5 5 5」と表示される
この場合、画面には「5 5 5 5 5」と出力されます。
3行目の関数の定義部分がポイントで、ここでは「変数iを参照するという関数定義」が5回行われています。
これはあくまでも変数への参照で、0、1、2、3、4の値では無いということです。
iの値は変化していますが、関数そのものはiを参照するという同じ定義を繰り返しています。
func.push(function(){return i});
次が、8行目の関数の実行部です。
str += func[j]() + " ";
この時点での変数iの値は、ループを止めた5になっています。したがって、それぞれの関数はすべて参照値である5を出力することになります。
ここでは、関数を実行する度に、それぞれの関数ごとにActivation Objectiが生成されスコープチェーンが形成されるということが行われています。
それぞれのActivation Objectのプロパティiの値にはすべて5がセットされています。
意図通りにするためには
それでは、意図通りに出力するためにはどうした良いのでしょうか。
最初のループは
1. 変数iの変化
2. 関数の定義(変数iへの参照)
1と2の繰り返しでスコープチェーンが形成されていないため、この時点では変数iの値が見えません。
次のループでは
1. 変数iは最初のループ終了で5になっている
2. 関数が実行される
3. 関数の実行でスコープチェーンが形成される
4. 変数iが見えるようになったが値が5になっているので、値5を返す関数が出来上がる
1から4の繰り返しになり、すべての関数は5を返すことになります。
そこで、変数iの値が変化する度に関数を実行してしまえば、その都度スコープチェーンが形成されて、意図通りに出力されるのではないでしょうか。
3行目を即時関数に変えてみました。
func.push(
(function(n){
return function(){return n;};
})(i)
);
定義と実行を同時に行いカウンタ変数iを引数にした関数です。
最初のループで
1. 変数iの変化
2. 関数の定義(変数iへの参照)
3. 関数の実行
4. スコープチェーンが形成される
5. 変数iの値が見えるので、それぞれの値(0~4)を返す関数の出来上がり
それぞれの値を返す関数が1サイクルごとに出来上がっています。
次のループでは
1. 各値を返す関数を実行する
その結果、意図通りに「0 1 2 3 4」と出力することができました。
スコープチェーンが形成されるタイミングをよく考えるということがわかりました。
カウンタ変数を再度使用したら
最初の例(うまくいかなかった例)では、関数実行部分のループでカウンタ変数をjとしていました。
試しにこの部分も最初のループを同様にiを使用してみました。
var func = [];
for (var i = 0; i < 5; i++) {
func.push(function(){return i;});
}
var result = document.getElementById("result");
var str = "";
for (var i = 0; i < func.length; i++) {
str += func[i]() + " ";
};
result.innerHTML = str; // 「0 1 2 3 4」と表示される
変数iを参照しているので、変数iが初期化されたことで結果的に即時関数の例と同じになります。