この記事は技術レビューを必要としています。ぜひご協力ください。
この記事は編集レビューを必要としています。ぜひご協力ください。
JavaScript は Web ページに多様なインタラクティビティをもたらすコンパクトな文 (statement) の集合体、特に制御フロー文をサポートしています。本章ではこれらの文の概要を説明します。
JavaScript リファレンスにはこの章で紹介した文についての完全な詳細が載っています。また、JavaScript のコードではセミコロン (;
) 文字で文を区切ります。
あらゆる式は、文でもあります。式に関する詳細については式と演算子を参照ください。
ブロック文
たいていの場合、ブロック文は文のグループ化に使います。ブロックは、1 組の波括弧で区切られます :
{ statement_1; statement_2; . . . statement_n; }
用例
ブロック文は一般に制御フロー文(例えば if
、for
、while
など)で用いられます。
while (x < 10) { x++; }
ここでは { x++; }
がブロック文となります。
重要 : ECMAScript 6 以前の JavaScript にはブロックスコープがありません。ブロック内で導入された変数のスコープは、そのブロックがある関数やスクリプトになります。またそれらの変数を設定した影響は、そのブロックを越えて持続します。つまり、ブロック文はスコープを定義しないということです。「独立した」ブロックも正しい構文ですが、C や Java のブロックで提供されるものとは異なる結果をもたらします。例えば :
var x = 1; { var x = 2; } console.log(x); // 2 を出力
ブロック内の var x
文はブロックの前の var x
文と同じスコープ内にあるため、この例では 2 が出力されます。C や Java では、同様のコードで 1 が出力されます。
ECMAScript 6 からは、let
文による変数宣言がブロックスコープとなります。詳しくは let
文の参考ページをご覧ください。
条件文
条件文は、指定した条件が true ならば実行される命令の集まりです。JavaScript は if...else
と switch
の 2 つの条件文をサポートしています。
if...else
文
論理条件が true の場合に、文を実行するには if
文を使用してください。オプションの else
節を使用すると、条件が false の場合にも文を実行することができます。if
文は次のように使用します :
if (condition) { statement_1; } else { statement_2; }
condition
には、true か false に評価される式が入ります。どういったものが true
や false
として評価されるかについては Boolean オブジェクトをご覧ください。condition
が true に評価された場合は statement_1
が実行され、そうでない場合は statement_2
が実行されます。statement_1
と statement_2
はどのような文でもかまいません。if
をさらに入れ子にすることもできます。
次のように else if
を使用して文を重ねることで、複数の条件を順々にテストすることができます :
if (condition_1) { statement_1; } else if (condition_2) { statement_2; } else if (condition_n) { statement_n; } else { statement_last; }
複数の文を実行するには、ブロック文 ({ ... }
) を使用してその文をグループ化してください。一般に、常にブロック文を使用するのが優れた方法です。特に if
文を入れ子にしたコードで有効です :
if (condition) { statement_1_runs_if_condition_is_true; statement_2_runs_if_condition_is_true; } else { statement_3_runs_if_condition_is_false; statement_4_runs_if_condition_is_false; }
条件式内で単純な代入を行わないでください。コードを一見した際に、代入を等値条件と見間違えるおそれがあるためです。例えば、次のコードにあげるような使用法はやめてください :
if (x = y) { /* ここに文が来る */ }
条件式で代入を行う必要がある場合、一般的な方法は代入式をさらに丸括弧でくくることです。例えば :
if ((x = y)) { /* ここに文が来る */ }
false と評価される値
以下の値は false に評価されます :
false
undefined
null
0
NaN
- 空の文字列 (
""
)
上記以外の、オブジェクトを含むすべての値は、条件文に渡されると true に評価されます。
プリミティブな真偽値の true
と false
を、Boolean
オブジェクトの true や false という値と混同しないでください。例えば :
var b = new Boolean(false); if (b) // この条件は true に評価される
用例
次の例で、関数 checkData
は Text
オブジェクトに含まれている文字数が 3 である場合に true を返し、そうでない場合はアラートを表示して false を返します。
function checkData() { if (document.form1.threeChar.value.length == 3) { return true; } else { alert("Enter exactly three characters. " + document.form1.threeChar.value + " is not valid."); return false; } }
switch
文
switch
文を使うと、プログラムは式を評価し、その式の値を case ラベルと照合します。マッチすると、プログラムはそのラベルに関連付けられた文を実行します。switch
文は次のようになります :
switch (expression) { case label_1: statements_1 [break;] case label_2: statements_2 [break;] ... default: statements_def [break;] }
プログラムはまず、式の値にマッチするラベルを持つ case
節を探します。そして制御をその節に移し、関連付けられた文を実行します。マッチするラベルがない場合、プログラムはオプションの default
節を探し、存在する場合は default
節に制御を移し、関連付けられた文を実行します。default
節がない場合、プログラムは switch
文の最後まで、後に続く文を実行し続けます。慣例により、default
節は最後の節に置きますが、そうしなければいけないわけではありません。
各 case
に関連付けられたオプションの break
文は、マッチした文を実行したら switch
文から抜けて、確実に switch 文以後の文を実行するためのものです。break
を省略した場合、プログラムはその switch
文内の次の文から実行を続けます。
用例
次の例では、fruittype
が "Bananas" に評価された場合は case "Bananas" にマッチして、それに関連付けられた文を実行します。break
文に出くわすとプログラムは switch
から抜けて、switch
の後に続く文を実行します。break
を省略すると、case "Cherries" の文も実行されます。
switch (fruittype) { case "Oranges": console.log("Oranges are $0.59 a pound."); break; case "Apples": console.log("Apples are $0.32 a pound."); break; case "Bananas": console.log("Bananas are $0.48 a pound."); break; case "Cherries": console.log("Cherries are $3.00 a pound."); break; case "Mangoes": console.log("Mangoes are $0.56 a pound."); break; case "Papayas": console.log("Mangoes and papayas are $2.79 a pound."); break; default: console.log("Sorry, we are out of " + fruittype + "."); } console.log("Is there anything else you'd like?");
例外処理文
throw
文を使用して例外を発生させる(例外をスローする)ことができます。また、try...catch
文を使用して例外を処理することができます。
例外の種類
JavaScript では、ほぼどのようなオブジェクトでも例外としてスローすることができます。とはいえ、必ずしもスローされるオブジェクトすべてが同等に作られているわけではありません。数値や文字列をエラーとしてスローする方法がよく用いられますが、こうした用途のために特別に作られた例外データ型を使用した方がより効率的な場合もあります :
throw
文
throw
文は、例外をスローするために使用します。例外をスローするには、スローしたい値を含む式を指定してください :
throw expression;
特定の型の式だけではなく、あらゆる式をスローすることができます。下記のコードでは、さまざまな型の例外をスローしています :
throw "Error2"; // String type throw 42; // Number type throw true; // Boolean type throw {toString: function() { return "I'm an object!"; } };
注記 : 例外をスローする際にオブジェクトを指定することができます。そして、catch
ブロックでそのオブジェクトのプロパティを参照できます。次の例では、UserException
という種類の myUserException
オブジェクトを作成します。
// UserException というオブジェクト型を作成 function UserException (message){ this.message=message; this.name="UserException"; } // 文字列として使用されるとき(例 : エラーコンソール上)に // 例外を整形する UserException.prototype.toString = function (){ return this.name + ': "' + this.message + '"'; } // UserException のインスタンスを作成し、それをスローする throw new UserException("Value too high");
try...catch
文
try...catch
文はテストしたい文のブロックを指定し、さらにスローされる例外に対する 1 つ以上の対処方法を指定します。例外がスローされると、try...catch
文がそれを受け取ります。
try...catch
文は 1 つの try
ブロックと 0 個以上の catch
ブロックで構成されます。try
ブロックは 1 つ以上の文を含み、catch
ブロックは try
ブロックで例外がスローされた場合の処理を指定する文が含まれます。要するに、成功した場合に実行したい try
ブロックと、失敗した場合に制御を移行させたい catch
ブロックで構成されています。try
ブロック内(もしくは try
ブロック内から呼び出された関数内)のいずれかの文が例外をスローすると、制御はすぐに catch
ブロックに移ります。try
ブロックで例外がスローされなかった場合、catch
ブロックはスキップされます。finally
ブロックは try
および catch
ブロックを実行した後に実行しますが、try...catch
文の後に続く文より先に実行されます。
次の例では try...catch
文を使用しています。この例では渡された値に基づいて、配列から月の名前を取り出す関数を実行します。値に対応する月の数字 (1-12) が無い場合は "InvalidMonthNo"
という値を持つ例外がスローされ、catch
ブロックの中の文は monthName
という変数に unknown
という値をセットします。
function getMonthName(mo) { mo = mo - 1; // 月の数字を配列のインデックスに合わせる (1=Jan, 12=Dec) var months = ["Jan","Feb","Mar","Apr","May","Jun","Jul", "Aug","Sep","Oct","Nov","Dec"]; if (months[mo]) { return months[mo]; } else { throw "InvalidMonthNo"; //throw キーワードが使われている } } try { // 実行を試みる文 monthName = getMonthName(myMonth); // この関数が例外をスローする場合がある } catch (e) { monthName = "unknown" logMyErrors(e); // 例外オブジェクトをエラーハンドラに渡す }
catch
ブロック
catch
ブロックを用いることで、try
ブロックで生じうるすべての例外を扱うことができます。
catch (catchID) { statements }
catch
ブロックには、throw
文で指定される値を保持しておく識別子(上記の構文における catchID
)を指定します。スローされた例外についての情報を得るのに、この識別子を使います。JavaScript は catch
ブロックに入るときにこの識別子を作成します。識別子は catch
ブロックの区間だけ存続します。つまり、catch
ブロックの実行が終わると、その識別子はもう使えなくなります。
例えば、次のコードは例外をスローします。例外が生じると、制御が catch
ブロックに移ります。
try { throw "myException"; // 例外を生成 } catch (e) { // ここには例外を扱う文が入る logMyErrors(e); // 例外オブジェクトをエラーハンドラに渡す }
finally
ブロック
finally
ブロックは、try
および catch
ブロックの実行が終わった後に、try...catch
文の後に続く文よりも先に実行される文で構成されます。finally
は例外がスローされてもされなくても実行されます。例外がスローされた場合、finally
ブロック内の文はたとえ例外処理をする catch
ブロックがなくても実行されます。
finally
ブロックを使用することで、例外発生時に適切にスクリプトを停止させることができます。例えば、スクリプトで使用していたリソースを解放しなければならないとします。次の例ではファイルを開き、そのファイルを使用する文を実行します (サーバサイド JavaScript ではファイルにアクセスできます)。ファイルを開いている間に例外がスローされると、スクリプトが停止する前に finally
ブロックでそのファイルを閉じます。
openMyFile(); try { writeMyFile(theData); // ここでエラーがスローされる可能性がある }catch(e){ handleError(e); // エラーを受け取り、それを処理する }finally { closeMyFile(); // 常にリソースが閉じられる }
finally
ブロックが値を返す場合、その値は try
および catch
ブロックの return
文にかかわらず、try-catch-finally
全体が生成する戻り値になります :
function f() { try { console.log(0); throw "bogus"; } catch(e) { console.log(1); return true; // この戻り値は、finally ブロックが // 完了するまで保留となる console.log(2); // この先は実行されない } finally { console.log(3); return false; // 直前の "return" が上書きされる console.log(4); // この先は実行されない } // ここで "return false" が実行される console.log(5); // この先は実行されない } f(); // 0, 1, 3 がログに表示され、false が返される
try...catch 文のネスト
1 つ以上の try...catch
文を入れ子にすることができます。内側の try...catch
文に catch
ブロックがない場合、囲んでいる try...catch
文の catch
ブロックがエラーの照合先としてチェックされます。
Error
オブジェクトの活用
エラーの種類に応じてより手の込んだメッセージが得られるように、'name' および 'message' プロパティを使うことができます。'name' はエラーの一般的なクラス(例えば 'DOMException' や 'Error')を表し、一方 'message' は通常、Error オブジェクトを文字列に変換したものより簡潔なメッセージを表します。
独自の例外をスローして、これらのプロパティを有効に活用したい場合(catch ブロックで独自の例外とシステムの例外とを区別したくない場合など)、Error コンストラクタが使えます。例えば :
function doSomethingErrorProne () { if (ourCodeMakesAMistake()) { throw (new Error('The message')); } else { doSomethingToGetAJavascriptError(); } } .... try { doSomethingErrorProne(); } catch (e) { console.log(e.name); // 'Error' とログに表示される console.log(e.message); // 'The message'、または // JavaScript のエラーメッセージがログに表示される }
Promise
ECMAScript 6 から、JavaScript には遅延・非同期処理の制御フローを可能にする Promise
オブジェクトのサポートが追加されました。
Promise
は以下にある状態の一つを取ります :
- pending (処理待ち / 未決): 初期状態で、承認も拒否もされていない状態。
- fulfilled (承認 / 可決): 処理が成功した状態。
- rejected (拒否 / 否決): 処理が失敗した状態。
- settled (解決): Promise オブジェクトが処理待ちでなく、承認か拒否された状態。
XHR を使った画像のロード
画像のロードに Promise
と XMLHttpRequest
を使った分かりやすい例が MDN GitHub promise-test リポジトリで利用できます。実際の動きも確認できます。それぞれのステップにはコメントが付けられ、Promise と XHR の基本概念をじっくりと観察することができます。 下記にあるのはコメントのないバージョンですが、Promise
の制御フローが手に取るようにわかると思います。 :
function imgLoad(url) { return new Promise(function(resolve, reject) { var request = new XMLHttpRequest(); request.open('GET', url); request.responseType = 'blob'; request.onload = function() { if (request.status === 200) { resolve(request.response); } else { reject(Error('Image didn\'t load successfully; error code:' + request.statusText)); } }; request.onerror = function() { reject(Error('There was a network error.')); }; request.send(); }); }
詳細については、Promise
オブジェクトのリファレンスページをご覧ください。