if ... else文で、{}を忘れて複数の文を記述すると、普通はコンパイルエラーになるが、else以下がない場合に{ }を忘れた場合や、else以下の{ }を忘れた場合は、正しい構文になる。期待した結果にならないことがあるので要注意だ。else以下の{ }を忘れた場合の例を見てみよう。
var c, t: string;
var h: number, d: Date;
d = new Date();
h = d.getHours();
if (h < 12) {
t = "午前のページ";
c = "skyblue";
} else
t = "午後のページ"; // (1)
c = "lightyellow"; // (2)
document.title = t;
document.body.style.backgroundColor = c;
このプログラムは、正しくコンパイルされ、実行できるので、問題はなさそうに見えるが、午前中にこのプログラムを実行すると期待した結果が得られない。タイトルバーまたはタブには「午前のページ」と表示されるのだが、ページの背景色は午後の色であるlightyellowになってしまう。
elseの後に{}がないと、elseの範囲が(1)の文だけになってしまうので、(2)の文はif ... else文の範囲外の、次の文になる。この結果、午前であっても午後であっても(2)が実行されるので、期待した結果が得られないというわけだ。
コラムに示した方法で、プログラムを清書すれば(2)のインデントが変わって、if ... else文の範囲外にあることが分かるのだが、こういうトラブルを防ぐためにも、条件を満たしたときやそうでないときに実行される文が1つの場合でも{ }を付けるようにしておくといい。
条件分岐では、このような単純なミスだけでなく、特定の条件の場合に実行する文に間違いがあると、問題に気付かなかったり、気付くのが遅れたりすることがあるので注意が必要だ(普通、プログラムのテスト時には、全ての分岐を通るようなデータを使って結果を確かめたり、分岐点となる値や最大値、最小値などの限界値を使って問題が起こらないかどうか確かめたりする)。
ただし、条件を満たしたときに実行する文が単純なもので(代入文が1つだけなど)、else以下がない場合には、1行に書いてしまった方が簡潔なコードになる。
var c: string;
var h: number, d: Date;
d = new Date();
h = d.getHours();
c = "lightyellow"; // (1)
if (h < 12) c = "skyblue"; // (2)
document.body.style.backgroundColor = c;
この例では、(1)でデフォルトの背景色を「lightyellow」としておき、午前中の場合にだけ(2)で背景色を「skyblue」にする。動作は最初のプログラムと同じだが、考え方は少し違う。それはさておき、(2)のような場合は、わざわざ{ }で囲むよりもプログラムが簡潔になる。
なお、コンパイルされたJavaScriptのコードでは、()の後で改行される。
JavaScriptには「等しい」ということを表すための演算子に==演算子と===演算子があります。==演算子は、必要に応じてデータ型を変換して値が等しければtrueを返します。しかし、===演算子はデータ型を変換せず、厳密に等しいかどうかを調べます。例を見てみましょう。
このプログラムはTypeScriptではコンパイルエラーになります。aの値は数値の1ですが、「"1"」は文字列で、データ型が異なるからです。しかし、JavaScriptのプログラムは作成され、実行もできます。この場合、データ型が変換され、結果はtrueになります。
(1)の比較演算子を「===」に書き替えると、TypeScriptではやはりコンパイルエラーになりますが、JavaScriptとして作成されたプログラムは実行ができます。この場合は、データ型が変換されないので、結果はfalseになります。
比較の対象がオブジェクトを参照する変数である場合には、同じオブジェクトを参照しているかどうかが調べられるので、データ型も値も同じなのにfalseとなることがあります。
var x1: String = new String("hoge"); // (1)
var x2: String = new String("hoge"); // (2)
alert(x1 == x2);
この例では、比較演算子を「==」にしても「===」にしても結果はfalseです。(1)と(2)では(値は同じですが)異なるオブジェクトを作成しており、x1とx2はそれぞれ異なるものを参照しているのでfalseになるというわけです。(2)を以下のように書き替えれば比較演算子が「==」でも「===」でも、結果はtrueになります。
var x2 = x1; // x2にx1の参照を代入
オブジェクトとプリミティブ型の比較であれば、「==」演算子ではデータ型が変換された上で等しいかが調べられ、「===」演算子では厳密に等しいかどうかが調べられます。以下のプログラムで確認できます。
var x1: String = new String("hoge");
var x2: string = "hoge";
alert(x1 == x2); // (1)
(1)の比較演算子が「==」の場合、結果はtrueになります。しかし、「===」に書き替えると、結果はfalseです。Stringクラスのオブジェクトとプリミティブ型の文字列(string型)は異なるものであることに注意が必要です。ただし、プリミティブ型のstringもオブジェクトであるかのようにふるまうことができます(一時的にオブジェクトが作成され、Stringクラスのメソッドが使えます)。クラスとオブジェクトについてはまだまだ先の話ですが、さまざまな興味深い仕組みがあるので楽しみにしていてください。
if ... else文には他にもいくつか注意すべき点があるのだが、先にネストについて見ておき、後でさらに落とし穴の例を見ることとしよう。
Copyright© Digital Advantage Corp. All Rights Reserved.