プログラムの制御構造
プログラムは記述したとおりに、命令文を上の行から順番に処理されます。制御構造は、その実行順番を制御するためのもので、条件分岐やループなどの構成要素があります。
条件分岐
「もし~ならば、・・・を実行する」という条件つき命令は、プログラムの流れを制御するときによく利用されます。JavaScriptでは、if else文とswitch文をサポートしています。
if else
if~else 文は、カッコ( () )で囲んだ条件式を評価し、式の値が真なら if ブロック内の命令を、偽りなら else ブロック内の命令を実行します。
構文
if ( 条件式 ) { 1つ目のifブロック内の命令 } else if ( 条件式 ) { 2つ目のifブロック内の命令 } else { elseブロック内の命令 }
次の式のように、条件式が真の場合、if ブロックが処理されて true が出力されます。もし、式の値が偽りであれば、else ブロックが処理されて false が出力されます。
// 条件式の値が true の場合 if ( true ){ console.log("true"); // 条件式の値が false の場合 } else { console.log("false"); }
true
if と else の組み合わせは、if で指定した条件式が真の場合と、偽りの場合の2択で条件分岐されます。それ以上の分岐が必要な場合は、else if を使います。else if は、if の条件式とは別の条件式を指定することができます。
次の文は、変数 x の値が「A」の場合は if ブロック、「B」の場合は else if ブロック、どちらにも当てはまらない場合は else ブロック内の命令文が処理されます。
// x の値で処理を分岐させる if ( x == "A" ){ // else ifは必要なだけ増やせる } else if ( x == "B" ) { // どの条件式にも当てはまらなかった場合 } else { }
else if、else は省略可能で、if のみにすることもできます。例えば、変数 x の値が「A」の時だけ出力するには次のようになります。
if ( x == "A" ) { console.log( x ); }
さらに、if に続く命令が1行のときには、{ } を省略することができます。次の行からは if 文の結果とは関係なく処理されます。
// 上記と同じ文で {} を省略 if ( x == "A" ) console.log( x );
if や else if は、複数の条件式を論理演算子の && 、もしくは || を使って組み合わせることができます。
// x の値が A、 もしくはB のとき if ( x == "A" || x == "B" ){ .... } // x の値が A、なおかつ y の値が B のとき if ( x == "A" && y == "B" ){ .... }
[COLUMN] 処理速度を考えた書き方
条件分岐が複数ある場合、どの条件式を先にするか順番も考えるようにしましょう。例えば、変数 x の値で条件分岐する if 文があり、xの値で最も可能性が高いのが「C」だったとします。
// xの値が「C」の場合、この条件分岐は飛ばされる if ( x == "A" ){ // xの値が「C」の場合、この条件分岐は飛ばされる } else if ( x == "B" ) { // xの値が「C」の場合、この条件分岐が処理される } else if ( x == "C" ) { }
上記のような条件分岐の順番だと、3番目の条件分岐にたどり着くまで2回、条件式の評価が行われます。もし3番目の条件式が一番上であれば、論式式の評価は1回だけで済んでいました。
効率を考えると、可能性の高い条件分岐から順番に評価するのがベストです。
// xの値が「C」の場合、この条件分岐が処理される if ( x == "C" ){ } else if ( x == "A" ) { } else if ( x == "B" ) { }
読みやすさなどを考えると必ずしも上記の書き方だけが正解とはいえないので、読みやすさや、無駄な処理が発生しないかなどを複合的に考えて、条件分岐の順番を決めると良いでしょう。
switch
switch 文は、一つの式を評価し、その値にマッチするラベルに制御を移します。
switch ( 式 ) { case 値: 処理 break; case 値: 処理 break; default: 処理 break; }
if 文は else if でどのような条件式でも使えますが、switch 文は一つの式の値で処理を分岐させます。
switch 文の処理の流れとしては、まず式が評価され、その値とマッチする case ラベルが上から順番に検索されます。case で指定した値と式の値がマッチした場合、関連した命令文が実行されます。
次のような if 文と同じ処理になる switch 文を作ってみましょう。まずは if 文です。
if ( x == "A" ){ // ここに命令文を記述 } else if ( x == "B" ) { // ここに命令文を記述 } else { // ここに命令文を記述 }
次に switch 文です。switch 文の場合、if、else if の代わりに case を使って分岐させ、else の代わりに default を使います。
switch ( x ) { case "A": // ここに命令文を記述 break; case "B": // ここに命令文を記述 break; default: // ここに命令文を記述 break; }
defualt は case に当てはまらなかった場合に、そのブロック内の命令文が必ず実行されます。default は省略可能です。
break ラベルは switch の処理を終了させます。 break を省略した場合、マッチした case ブロックの処理が終わった後、以降のラベルもそのまま評価されます。
if 文の方がシンプルに使え、条件式により条件分岐するため、殆どの条件分岐では if 文が使われます。値によって条件分岐したいとき、switch 文を使うことを検討すると良いでしょう。
ループ
JavaScriptはfor文とwhile文の2つのループ構造をサポートします。
ループは指定された条件が満たされるまで、くり返し命令文を処理します。
for
for 文は、指定された条件式が false になるまで処理を繰り返します。
for ( 初期化式; 条件式; 増加文 ) { 命令文 }
for 文の処理を追っていくと、まず、初期化式でループカウンタと呼ばれる、ループ処理の回数を決める変数を初期化します。この初期化式は、最初の1回だけ処理されます。
次に条件式が評価されます。条件式が true を返す間は、for 文のブロック内が繰り返し実行されます。条件式が false を返した場合、for ループが終了します。
増加文では指定した変数(通常はループカウンタ)をインクリメント、デクリメントします。
次のような for 文では、まず変数 i が 0 に初期化され、次に条件式が評価されます。この条件式は変数 i が5未満の間は true を返し、その間はブロック内の命令文を繰り返し実行します。すべての命令文が実行されると、また次のループへ戻る前に、増加文が評価されます。ここでは変数 i がインクリメントされます。
ループカウンタの変数名として、i、j、k がよく使われています。
for ( var i=0; i<5; i++ ) { console.log( i ); }
0 1 2 3 4
for 文を含む繰り返し文は、ループカウンタを使って繰り返し回数を制御します。for 文は、このループカウンタを初期化して、条件判定、更新を1行で設定することができるため、繰り返し分の中で最もよく使われています。
初期化式と増加文は複数の対象をカンマで区切って指定することができます。
for ( 初期化式, 初期化式, ...; 条件式; 増加文, 増加文, ... ) { 命令文 }
次の for 文は変数 i と変数 j を初期化し、i が3以下の間は繰り返しブロック内の命令文を実行します。増加文では i をインクリメント、j をデクリメントしています。
for ( var i = 1, j = 3; i <= 3; i++, j-- ){ console.log("i = " + i + " j = " + j); }
i = 1 j = 3 i = 2 j = 2 i = 3 j = 1
while
while 文は式が true(真)の間、ブロック内の命令文を繰り返し実行します。式が false になると、繰り返しを終了します。
while( 式 ){ 命令文 }
次の while 文は変数 x が3未満の間ループを繰り返します。
var x = 0; while( x < 3 ) { console.log(x+=1); x++; }
1 2 3
指定した式が false にならない場合、命令が永遠に実行されるので注意してください。下記では、変数 x が10で、式は変数 x が3以上であれば繰り返すので、無限に繰り返されてしまいます。
var x = 10; while( x > 3 ) { console.log(x); x++; }
do while
do while 文はまず do ブロックを実行し、式が真の間は while ブロックを繰り返し実行します。do ブロックを実行した後で式を判定するので、do ブロック内の命令文は少なくとも1回は実行されます。
構文
do { 命令文 } while ( 式 );
次の例文では、while の条件が true の間、do ブロック内の処理を続けます。
var i = 0; do { i++; console.log(i); } while ( i < 5 );
最低1回はブロックを実行したい、というケースが少ないため、do while 文はあまり使われていません。
break
break は while や for といった繰り返し構文や switch などの処理内で使われます。beak が実行されると直ちにそのループや switch 処理から抜けて次の命令文に移動します。
次の for 文では、変数 i が10未満の間繰り返されますが、ブロック内の if 文で、変数 i が3になった際に、break が実行されています。そのため、出力結果は0から2までとなります。
for ( var i = 0; i < 10; i++ ) { if ( i == 3 ) { break; } console.log(i); }
0 1 2
continue
while、for 文のブロック内で continue が評価されると、それ以降に続くブロック内の命令をスキップし、先頭ループへ戻ります。
conticue は break と同様に処理を中断させますが、その後ループの先頭に処理を戻します。次の for 文では、変数iが3のときに continue が実行されるので、0から2まで出力されたあと、3が飛ばされて、4が出力されています。
for ( var i = 0; i < 5; i++ ) { if ( i == 3 ) { continue; } console.log(i); }
0 1 2 4
オブジェクト操作命令
for~in
for in 文は、指定したオブジェクトのプロパティ名を取り出し、変数に代入します。オブジェクトから列挙可能なプロパティがある間、for in 文は繰り返し処理を続けます。
for ( 変数 in オブジェクト ) { 命令 }
次の例では、変数 obj を初期化し、for in を使ってすべての要素にアクセスしています。
var obj = {a:"A", b:"B", c:"C"}; for ( var o in obj ) { console.log("obj." + o + " : " + obj[o]); }
obj.a : A obj.b : B obj.c : C
for in は配列に対しても使うことができます。配列の場合はインデックスが変数に代入されます。
ただし、for in はインデックス以外にも、カスタムプロパティやカスタムメソッドなどもループ処理の対象となるので、配列の場合は通常の for ループを使ったほうが安全です。
var obj = ["A", "B", "C"]; for ( var i in obj ) { console.log( "obj." + i + " : " + obj[i] ); }
obj.0 : A obj.1 : B obj.2 : C
return
return は関数内で使います。return が実行されると、直ちに関数を終了します。return に値を指定すると、関数はその値を呼び出し元に返却します。
return 式
下記の関数は引数 x と y を乗算して返します。
function pow(x,y){ return x * y; } pow(2, 5)
10
with
with は、オブジェクトのプロパティやメソッドを頻繁に参照する際に使います。with で指定したオブジェクトは、そのブロック内で省略することができます。
with( オブジェクト ){ 命令 }
次の式は、Math オブジェクトの min() と max() を、オブジェクト名なしで参照しています。
var a = 5, b = 10; with ( Math ) { console.log( "最小:" + min( a, b ) ); console.log( "最大:" + max( a, b ) ); }
最小:5 最大:10
with は使用を推奨されていません。オブジェクトはバージョンにより変更されるため互換性にかけ、パフォーマンスもよくありません。