つくる 時間帯で挨拶を変える
このレッスンで分かること
- 両端のある範囲は、2 つの比較を
&&でつないで書きます- 飛び飛びの範囲は、拾いたい帯だけ条件で拾い、残りを
elseで受けます- 範囲の判定は、境目の前後だけ確かめれば足ります
60 以上 80 未満を、1 つの比較では書けない
範囲で分ける判定を書くとき、多くの人がまず数学の書き方を試します。
JavaScript
// NG。60 <= score の結果 (true か false) と 80 を比較してしまう
if (60 <= score < 80) { }構文エラーにならず、そのまま動いてしまうのが厄介です。まず 60 <= score が評価されて true か false になり、その真偽値と 80 が比べられます。真偽値は数として 1 か 0 に変換されるので、この条件はどんな値でも成立します。
両端のある範囲は、2 つの比較を && でつなぎます。
JavaScript
// OK
if (score >= 60 && score < 80) { }前のレッスンで「else if なら上限は書かなくてよい」と学びましたが、下限は事情が違います。score >= 60 を省くと、1 つ目の条件が false になるような小さい値まで拾ってしまいます。省いてよいのは、前の条件から論理的に導けるものだけです。
拾いたい帯だけ拾って、残りを else に落とす
範囲が飛び飛びになることがあります。時計のように 0 で 1 周する数を扱うと、同じ扱いにしたい帯が円環の切れ目をまたいで 2 か所に分かれます。else if は上から順に評価する構造なので、離れた 2 つの範囲はそのままでは書きにくいのです。
そこで発想を変えます。拾いたい帯だけを条件で拾い、残りを全部 else で受け止めるのです。こうすれば離れた範囲が 1 か所にまとまり、枝の数が減ります。仕様の表が 5 行あっても、コードの枝は 3 つで足りることがあります。書き始める前に、表を「どの順で拾うか」の形に組み替えてみてください。
実際のサイトでは現在時刻を
new Date().getHours()で取れます。ですが現在時刻に依存する関数はテストしづらいので、値は引数で受け取る形にします。「値を決める処理」と「値から答えを決める処理」を分けておくのは、実務でもよく使う設計です。
真ん中を 10 個試すより、境目を 4 つ
範囲の判定は、境目の前後だけ確かめれば足ります。下限、下限の 1 つ手前、上限、上限の 1 つ先。この 4 点が合っていれば、範囲の中身は自動的に正しくなります。
| 値 | 通ってほしい枝 |
|---|---|
59 | 1 つ手前の枝 |
60 | この枝 (下限) |
79 | この枝 (上限) |
80 | 次の枝 |
加えて、扱う値の下端と上端も 1 度ずつ流してください。どんな値もどれか 1 つの枝に必ず入ることを、自分の目で確かめておきます。
よくある間違い
- 上限と下限を両方
<=にする — 境目の値が 2 つの枝の両方に当てはまってしまいます
JavaScript
// NG。80 がどちらの枝にも当てはまる
if (score >= 60 && score <= 80) {
} else if (score >= 80 && score <= 100) {
}else if なら先に書いたほうが勝つので答えは出ますが、仕様の表と食い違ったまま気付けません。上限は <、下限は >= のように、片方だけが含む形にそろえてください。
- 最後を
else ifで終える — どの枝にも入らない値が出てundefinedが返ります。最後は条件を書かないelseで受け止めてください
要件
- 関数名は greetByHour、引数は 0 から 23 の整数 hour の 1 つ
- 5 以上 12 未満なら "おはようございます"、12 以上 18 未満なら "こんにちは" を返す
- それ以外の時刻はすべて else で受け止め、"こんばんは" を返す
- 範囲の判定は && で 2 つの比較をつなぎ、戻り値はすべて文字列にする
入出力例
greetByHour(0) → "こんばんは"
greetByHour(5) → "おはようございます"
greetByHour(12) → "こんにちは"
greetByHour(18) → "こんばんは"
greetByHour(23) → "こんばんは"