if文の基本構文
if文は、条件が真のときだけブロック内のコードを実行するための構文です。書き方としては、キーワードのあとに丸カッコで条件を書き、続けて波カッコでブロックを囲みます。
age >= 18 という条件が true になるので、ブロックの中身が実行されます。もし age が 16 だったら条件は false になり、ブロック全体がまるごとスキップされる、というわけです。
ブロックが1行だけの場合、波かっこは文法上は省略できます。でも、必ず書くようにしましょう。波かっこなしの if 文は、後から誰かが2行目を追加したときに「実はブロックの中に入っていなかった」というバグを生みがちな、典型的な落とし穴です。
else:条件に合わなかったときの分岐
if に else を組み合わせると、条件が false のときに別の処理を走らせることができます。
ふたつのブランチのうち、必ずどちらか片方だけが実行されます。両方実行されることも、どちらも実行されないこともありません。else は独自の条件を取りません。あくまで「if が false だったとき」の受け皿です。
else if:複数の選択肢から分岐する
3 つ以上のケースがあるときは、else if でつなげていきます。JavaScript は条件を上から順にチェックし、最初に true になったところで止まります。
一致した分岐だけが実行されます。条件がマッチした時点で、それ以降はたとえ true になる条件があっても飛ばされます。だからこそ順序が重要で、もし score >= 60 を最初にチェックするようにひっくり返してしまうと、60 点以上の人全員が D 判定になってしまいます。
最後の else は省略してもかまいませんが、書いておくと「どれにも当てはまらなかったらこれを実行する」という意図がはっきり伝わります。
条件式には何でも書ける
() の中身は比較式である必要はありません。どんな式でも書けて、JavaScript がその結果を自動的に真偽値(boolean)に変換してくれます。
中身のある文字列は truthy として扱われます。一方で 0 や空文字列は falsy なので、items.length が 0 のときは else 側に流れます。これは「中身があるかどうかをチェックする」ための、JavaScript らしい定番の書き方です。
falsy になる値は数が少ないので、覚えてしまうのが得策です。具体的には false、0、-0、0n、""、null、undefined、NaN の8つ。これ以外はすべて truthy で、"0" や "false"、[]、{} も truthy です。特に最後の2つ(空配列と空オブジェクト)は勘違いしやすいので注意してください。
条件を組み合わせる: && と ||
複数の条件をまとめたいときは、&&(かつ)と ||(または)を使います。
&& は両辺が truthy であることを要求し、|| は少なくとも片方が truthy なら OK です。どちらも短絡評価で、&& は最初の falsy な値で、|| は最初の truthy な値で評価を止めます。これは第二条件に副作用がある場合や例外を投げる可能性がある場合に効いてきます。たとえば user && user.name なら、user が null のときは undefined が返るだけで、エラーで落ちたりしません。
条件を組み合わせるときは、優先順位がひと目でわかるように括弧で囲んでおきましょう。
カッコを省くと && のほうが || よりも優先順位が高くなり、たいていの場合、読んで直感的に期待する挙動とは逆になってしまいます。
== と === の違い(基本は === を使う)
if 文の中で等価判定をするときは、== や != ではなく === と !== を使いましょう。
== は比較する前に型変換が走るので、"" == 0 が true になったり、null == undefined が true になったりと、思わぬ結果を招きます。一方 === は型変換なしで、型も値も一致しているかを見てくれます。基本は === を使いましょう。唯一よく使われる例外は x == null で、こう書くと null と undefined の両方をまとめてチェックできます。
三項演算子を使う
2つの値からどちらかを選ぶだけなら、if/else を丸ごと書くより三項演算子 condition ? a : b のほうがスッキリ書けることが多いです。
三項演算子は 式(expression) なので、値を返します。ここが if/else(こちらは文=statement)との決定的な違いです。変数に代入したい、値を return したい、文字列を組み立てたい——そんなふうに「結果の値」が欲しいときは三項演算子を使いましょう。一方、副作用のある処理を走らせたいときは if/else の出番です。
三項演算子はチェーン(入れ子)することも できます が、可読性は一気に崩壊します。
// こうしないでください:
const grade = score >= 90 ? "A" : score >= 80 ? "B" : score >= 70 ? "C" : "F";
チェーンで条件を並べたいときは、else if に戻しましょう。
ネストした if とフラットな else if
ある条件が、別の条件の内側でしか意味を持たないケースもあります。そういうときはネストさせて書いて問題ありません。
ただし、3〜4階層もネストしてしまうのは危険信号です。早期リターンや条件をまとめる書き方でフラットにしましょう。
early return を使うと、それぞれの分岐が短くなって、インデントも揃います。ネストが深くなったピラミッド状の if 文と比べると、ぐっと読みやすくなりますよ。
よくある落とし穴:if の中で代入してしまう
= は代入、=== は比較です。これを条件式の中で混同してしまうのは、典型的なバグの一つです。
status = "done" は status に "done" を代入したうえで、式としては "done" を返します。これは truthy なので、ブロックは必ず実行され、しかも変数の中身が気づかないうちに書き換わってしまいます。Linter なら検出してくれますが、strict モードでは引っかかりません。比較のつもりなら === を使う、これを徹底しましょう。
次は switch
1つの値を複数の候補と突き合わせたいとき、else if を延々と書き連ねるのはどうしても冗長になります。JavaScript の switch 文はまさにそのために用意されたもの。ただし break やフォールスルーといった独特のクセがあるので、次はそのあたりを見ていきます。
よくある質問
JavaScriptでif/else文はどう書きますか?
ifのあとに()で条件を書き、{}の中に実行したい処理を入れます。条件が偽のときの処理はelseのブロックに書きます。例えば if (age >= 18) { console.log('adult'); } else { console.log('minor'); } のような形です。条件には任意の式を書けて、JavaScriptが自動的に真偽値に変換してくれます。
else ifとネストしたifはどう違いますか?
else ifは複数の条件を順に評価して、最初にマッチしたブロックだけが実行されます。一方、ネストしたifは「1つ目の条件が真のときだけ、さらに別の条件を確認したい」といったケースで使います。基本的にはフラットなelse ifのほうが読みやすく、深くネストしたifは避けるのが無難です。
if/elseではなく三項演算子を使うのはどんなとき?
condition ? a : b の形は「2つの値のどちらかを選ぶ」ような式の中で使うのが向いています。変数への代入、関数の戻り値、文字列の組み立てなどですね。反対に、分岐の中で副作用のある処理を書くときや、それぞれのブロックが数行にわたるときは素直にif/elseを使ったほうが読みやすいです。三項演算子を何段もつなげるとすぐ読めなくなるので注意。
if (0) と if (false) の挙動は違いますか?
いえ、どちらもブロックはスキップされます。JavaScriptは条件を真偽値に変換する際、0・''・null・undefined・NaN・falseをすべてfalsyとして扱うためです。ハマりやすいのは逆で、'0'(空でない文字列)や[](空の配列)はtruthy扱いになる点。他の言語から来ると結構驚くポイントです。