つくる 時間帯で挨拶を変える
このレッスンで分かること
- この章で学んだ
if/else if/ 論理演算子を組み合わせて 1 つの機能を作れます- 範囲で分ける判定は、境界値をどちらに含めるかを先に決めます
- 0 時から 23 時までの全部の値が、どれか 1 つの枝に必ず入ることを確認します
つくる 時間帯で挨拶を変える とは
0 から 23 の時刻を受け取って、時間帯に合った挨拶を返す関数を作ります。第 4 章の総まとめとして、プロフィールサイトの表示を時間で変える機能を仕上げます。
ここまでで何ができるようになったか
第 4 章では、条件によって処理を分ける道具を一通り学びました。振り返っておきましょう。
| レッスン | 学んだこと | 使いどころ |
|---|---|---|
| if 文の基本 | if / else で 2 分岐 | 条件を満たすかどうかの 2 択 |
| if / else if / else | 3 つ以上の段階判定 | 数値の範囲で分ける |
| switch 文 | 値ごとの分岐と break | 決まった候補から 1 つ選ぶ |
| 条件を組み合わせる | 論理演算子でネストをフラットに | 判定材料が 2 つ以上ある |
| FizzBuzz | 狭い条件を先に書く | 条件が重なるとき |
今回はこのうち、範囲の段階判定と論理演算子を使います。作るのは、プロフィールサイトの上部に出す挨拶メッセージです。朝に訪れた人には「おはようございます」、昼なら「こんにちは」、夜なら「こんばんは」。同じページでも時間によって表情が変わる、小さな仕掛けです。
実際のサイトでは現在時刻を
new Date().getHours()で取れます。しかし現在時刻に依存する関数はテストしづらいので、今回は時刻を引数で受け取る形にします。「時刻を決める処理」と「時刻から挨拶を決める処理」を分けておくのは、実務でもよく使う設計です。
仕様を表にする
コードを書く前に、仕様を表に落とします。段階判定のレッスンで身に付けた手順です。
| 時刻 | 時間帯 | 戻り値 |
|---|---|---|
| 0 時から 4 時 | 深夜 | "こんばんは" |
| 5 時から 11 時 | 朝 | "おはようございます" |
| 12 時から 17 時 | 昼 | "こんにちは" |
| 18 時から 23 時 | 夜 | "こんばんは" |
深夜と夜は同じ挨拶にします。時計の 0 時をまたいで連続している時間帯なので、扱いをそろえたほうが自然です。
ここで注目してほしいのは、"こんばんは" を返す範囲が 2 つに分かれていることです。時刻は 0 から 23 で 1 周する数字なので、範囲が円環の切れ目をまたぐと 2 か所に分かれます。この形は else if の並びと相性がよくありません。上から順に評価する構造では、飛び飛びの範囲は書きにくいのです。
そこで発想を変えます。朝と昼だけを条件で拾い、残りを全部 else で受け止めるという順番にすれば、飛び飛びの範囲を 1 か所にまとめられます。
| 順番 | 条件 | 戻り値 |
|---|---|---|
| 1 | 5 以上 12 未満 | "おはようございます" |
| 2 | 12 以上 18 未満 | "こんにちは" |
| 3 | それ以外 | "こんばんは" |
3 つ目の else が受け止めるのは 0 から 4 と 18 から 23 です。表が 5 行から 3 行に減りました。条件の書き方を工夫すると、コードはこれだけ短くなります。
範囲を && で書く
「5 以上 12 未満」のように上下の両端がある範囲は、&& でつなぎます。
if (hour >= 5 && hour < 12) {
return "おはようございます";
}数学のように 5 <= hour < 12 と書くことはできません。この書き方は構文エラーにはなりませんが、まったく違う意味になります。5 <= hour がまず評価されて true か false になり、その真偽値と 12 が比較されるからです。必ず && で 2 つの比較をつないでください。
前のレッスンで「
else ifなら上限を書かなくてよい」と学びました。今回は事情が違います。2 つ目の条件hour >= 12 && hour < 18の下限hour >= 12は省略できません。1 つ目の条件がfalseになるのはhourが3のような小さい値のときもあるからです。省略してよいのは、前の条件から論理的に導けるものだけだと覚えてください。
書き上がりは次のようになります。
function greetByHour(hour) {
if (hour >= 5 && hour < 12) {
return "おはようございます";
} else if (hour >= 12 && hour < 18) {
return "こんにちは";
} else {
return "こんばんは";
}
}境界値で確かめる
書けたら、必ず境界値で動きを確かめます。範囲の切れ目にあたる時刻を全部並べて、期待どおりかを 1 つずつ見ていきます。
| 時刻 | 通る枝 | 戻り値 |
|---|---|---|
0 | else | "こんばんは" |
4 | else | "こんばんは" |
5 | 1 つ目 | "おはようございます" |
11 | 1 つ目 | "おはようございます" |
12 | 2 つ目 | "こんにちは" |
17 | 2 つ目 | "こんにちは" |
18 | else | "こんばんは" |
23 | else | "こんばんは" |
4 と 5、11 と 12、17 と 18 という 3 組の境目で、答えが切り替わっていることを確認してください。この 6 つの値さえ合っていれば、範囲の中身は自動的に正しくなります。範囲判定のテストは、境目の前後だけを見れば十分だという考え方です。
境界値のテストは、実務でもまったく同じ手順で行います。「範囲の下限、下限の 1 つ手前、上限、上限の 1 つ先」の 4 点を押さえるだけで、範囲判定のバグはほぼ防げます。真ん中の値を 10 個試すより、境目を 4 つ試すほうがずっと効きます。
プロフィールサイトに組み込む
できた関数は、テンプレートリテラルと組み合わせて使います。
const name = "山田 太郎";
const hour = 9;
console.log(`${greetByHour(hour)}、${name} のページへようこそ`);
// => おはようございます、山田 太郎 のページへようこそ挨拶を決める部分が関数に閉じ込められているので、呼び出す側は時間帯を気にする必要がありません。第 8 章で DOM を学べば、この文字列をそのままページの見出しに流し込めるようになります。今日書いた関数は、そのときにそのまま使えます。
よくある間違い
- 範囲を数学の形で書く — 前述のとおり、意図しない結果になります。
// NG。5 <= hour の結果 (true か false) と 12 を比較してしまう
if (5 <= hour < 12) {
// OK
if (hour >= 5 && hour < 12) {- 境界値を重複させる —
hour <= 12とhour >= 12を両方書くと、12 時がどちらの枝にも当てはまります。else ifなら先に書いたほうが勝つので結果は出ますが、表と食い違ったまま気付けません。上限は< 12、下限は>= 12のように、片方だけが含む形にそろえてください。
// NG。12 時が朝と昼の両方に当てはまる
if (hour >= 5 && hour <= 12) {
return "おはようございます";
} else if (hour >= 12 && hour <= 18) {
return "こんにちは";
}
// OK
if (hour >= 5 && hour < 12) {
return "おはようございます";
} else if (hour >= 12 && hour < 18) {
return "こんにちは";
}elseを書かずに終える — 3 つ目をelse if (hour >= 18)と書いてしまうと、0 時から 4 時がどの枝にも入らずundefinedが返ります。すべての値がどれか 1 つの枝に必ず入ることを、0と23を手で流して確かめてください。
要件
- 関数名は greetByHour、引数は 0 から 23 の整数 hour の 1 つ
- 5 以上 12 未満なら "おはようございます"、12 以上 18 未満なら "こんにちは" を返す
- それ以外の時刻はすべて else で受け止め、"こんばんは" を返す
- 範囲の判定は && で 2 つの比較をつなぎ、戻り値はすべて文字列にする
入出力例
greetByHour(0) → "こんばんは"
greetByHour(5) → "おはようございます"
greetByHour(12) → "こんにちは"
greetByHour(18) → "こんばんは"
greetByHour(23) → "こんばんは"