お蔵出しシリーズ2。2008年2月に書いたらしいものに加筆したら原型がなくなりました。
ループ文とは
通常は上から下に処理が進んでいくプログラムを、一定条件に当てはまるあいだだけ繰り返し処理する制御文。
for文
初期値、条件、増減式を設定して、条件が真であるあいだ、一定の処理を繰り返す命令。
正確に言うと条件が偽になったら処理をしないでループを抜ける、ってことになる。
ループ用の変数に初期値(数値)を代入して、それを増減してループ回数を制御する。なので、主にループ回数が開始前に設定できる場合に使う。
for( 式1 ; 式2 ; 式3 ) {
繰り返したい処理
}
- 式1
- 初期値を設定する式。ループ開始前に一度だけ評価される。
- 式2
- 条件式。毎回のループの最初に評価され、もしも偽(false)だったら{}内の処理を行わずにループを抜ける。
- 式3
- ループ用の変数の値を増減する式。後処理。毎回のループの最後に評価される。式2が偽になった場合はその時点でループを抜けてしまうので、この式は実行されない。
ちなみに、式1と式3には複数の式を書くことができる。その場合は式をカンマ , で区切ること。
例えば「配列arrの要素を順番にすべて書き出す」みたいな処理をしたい場合、
var arr = [10, 20, 30, 40];
for( var i = 0 ; i < arr.length ; i++ ) {
alert( arr[i] );
}
って書いてもいいんだけど、これだと式2にあたる「 i < arr.length 」の評価時にいちいち配列の要素数を調べることになる。
var arr = [10, 20, 30, 40];
for( var i = 0 , arr_len = arr.length ; i < arr_len ; i++ ) {
alert( arr[i] );
}
こうすれば、要素数を調べる処理はループ開始前の一回だけで済む。ループ回数が最初に固定できる場合は、採用すると処理が早くなるかも。
while 文
条件を設定し、それが真である間、一定の処理を繰り返す命令。
while( 条件式 ) {
繰り返したい処理
}
初期値の設定や後処理がないので、ループ内で条件を変更するか、break(後述)とかでループを抜ける必要がある。でないと無限ループになる。
while(true) {
breakがなければ無限ループされる処理
}
forのところで書いた「配列arrの要素を順番にすべて書き出す」処理をwhile文でやる場合、
var arr = [10, 20, 30, 40];
var i = 0, arr_len = arr.length;
while( i < arr_len ) {
alert( arr[i] );
i++;
}
って書くと、for文とまったく同じことができる。
もうちょっと抽象化すると、
for( 式1 ; 式2 ; 式3 ) {
繰り返したい処理
}
と
式1;
while( 式2 ) {
繰り返したい処理
式3;
}
が同じということ。
でもwhileでこれをやるくらいなら素直にfor使えばいいと思う。
whileの場合、たとえばarrを破壊してしまってもいいなら以下のようなことができる。
var arr = [10, 20, 30, 40];
while( arr.length ) {
alert( arr.shift() );
}
Array.shift()は配列から最初の要素を取り除き、その要素を返す。
ループのたびに配列arrから要素がひとつずつ減っていって、要素がなくなったら次のループ開始時には条件式「 arr.length 」が0(真偽値に変換するとfalse)になるので、ループを抜ける。
複数行にわたる文字列を取得して、一行ずつ最後まで処理したい場合なんかに使える。
do-while 文
while文と似てるけど、これは一度は必ず一定の処理を行い、その後、条件が真のあいだだけ同じ処理を繰り返す場合に使う命令。
do {
一度は必ず行うけど、もしかしたら繰り返したいかもしれない処理
} while( 条件式 )
for文やwhile文の場合、条件式が最初からfalseだったらその時点でループを抜けてしまうので、{}内の処理は一度も行われない。
do-while文では、条件式は{}内の処理が行われた後に評価される。なので条件式の結果がどうであっても、とりあえず一度は必ず処理が行われる。
つっても、今までこれ使う機会は一度もなかったんだが……
break文、continue文
ループの途中で処理の流れを中断したい場合に使う命令文。
breakの場合は処理を中断し、直ちにループを抜け、次の処理に移る。
for( var i = 0 ; i < 10 ; i++ ) {
if( i==5 ) {
break;
alert( "ここは処理されない" );
}
alert( "i = " + i );
}
alert( "ループ外 i = " + i );
breakでループを抜けた場合、ループ終了時の処理(「i++」の部分)は行われていない。
continueの場合は、直ちにその回のループ終了処理を行う。
for( var i=0 ; i<10 ; i++ ) {
if( i==5 ) {
continue;
alert( "ここは処理されない" );
}
alert ( "i = " + i );
}
alert( "ループ外 i = " + i );
while文の場合は、条件の変更前にcontinueを置いてしまうと無限ループになるので注意。
for-in文
for-in文はfor文から派生した構文。
配列の各要素……というか、オブジェクトの各プロパティにアクセスして、同じ処理を繰り返す場合に使う。
var arr = [10, 20, 30, 40];
for( var i in arr ) {
alert( arr[i] );
}
ちなみに i にはオブジェクトのプロパティ名(文字列)が入る。
var arr = [10, 20, 30, 40];
for( var i in arr ) {
alert( i + " : " + typeof i );
}
数値に見えるけど文字列。
例は配列で書いたけど、実はfor-inは配列に使わないほうがいい。
以下は理由。わからなければ「使っちゃいけないのねフーン」でいいと思う(よくないけど)。
for-in構文は「オブジェクトのプロパティ」にアクセスするので、例えば他のところでArrayオブジェクトが拡張された場合、そのプロパティまで列挙してしまう。
Array.prototype.hoge = function(){ alert("ほげー"); };
var arr = [10, 20, 30, 40];
for( var i in arr ) {
alert( arr[i] );
}
オブジェクト(インスタンス)自身が持っているプロパティだけを列挙したいときは、都度hasOwnProperty()で判定すればOK。
Array.prototype.hoge = function(){ alert("ほげー"); };
var arr = [10, 20, 30, 40];
for( var i in arr ) {
if(arr.hasOwnProperty(i)){
alert( arr[i] );
}
}
var arr = [10, 20, 30, 40];
arr.hoge = function(){ alert("ほげー"); };
for( var i in arr ) {
if(arr.hasOwnProperty(i)){
alert( arr[i] );
}
}
for-inのループはプロパティを定義した順番で行われる(正確には、プロパティに値を代入した順番)。
また、プロパティの値が定義されていないものは無視される。
var obj = new Object;
obj.age;
obj.name = "権兵衛";
obj.age = "20";
obj.addr = "ちば";
obj.hobby;
for( var i in obj ) {
alert( i + " : " + obj[i]);
}
疲れたのでこの辺で切り上げ。