つくる 時間帯で挨拶を変える

生田 陸人
ゆめさくエンジニア / 現役ソフトウェアエンジニア
編集 LuaGate編集部

このレッスンで分かること

  • この章で学んだ if / else if / 論理演算子を組み合わせて 1 つの機能を作れます
  • 範囲で分ける判定は、境界値をどちらに含めるかを先に決めます
  • 0 時から 23 時までの全部の値が、どれか 1 つの枝に必ず入ることを確認します

つくる 時間帯で挨拶を変える とは

0 から 23 の時刻を受け取って、時間帯に合った挨拶を返す関数を作ります。第 4 章の総まとめとして、プロフィールサイトの表示を時間で変える機能を仕上げます。

ここまでで何ができるようになったか

第 4 章では、条件によって処理を分ける道具を一通り学びました。振り返っておきましょう。

レッスン学んだこと使いどころ
if 文の基本if / else で 2 分岐条件を満たすかどうかの 2 択
if / else if / else3 つ以上の段階判定数値の範囲で分ける
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 か所にまとめられます。

順番条件戻り値
15 以上 12 未満"おはようございます"
212 以上 18 未満"こんにちは"
3それ以外"こんばんは"

3 つ目の else が受け止めるのは 0 から 4 と 18 から 23 です。表が 5 行から 3 行に減りました。条件の書き方を工夫すると、コードはこれだけ短くなります。

範囲を && で書く

「5 以上 12 未満」のように上下の両端がある範囲は、&& でつなぎます。

if (hour >= 5 && hour < 12) { return "おはようございます"; }

数学のように 5 <= hour < 12 と書くことはできません。この書き方は構文エラーにはなりませんが、まったく違う意味になります。5 <= hour がまず評価されて truefalse になり、その真偽値と 12 が比較されるからです。必ず && で 2 つの比較をつないでください。

前のレッスンで「else if なら上限を書かなくてよい」と学びました。今回は事情が違います。2 つ目の条件 hour >= 12 && hour < 18 の下限 hour >= 12 は省略できません。1 つ目の条件が false になるのは hour3 のような小さい値のときもあるからです。省略してよいのは、前の条件から論理的に導けるものだけだと覚えてください。

書き上がりは次のようになります。

function greetByHour(hour) { if (hour >= 5 && hour < 12) { return "おはようございます"; } else if (hour >= 12 && hour < 18) { return "こんにちは"; } else { return "こんばんは"; } }

境界値で確かめる

書けたら、必ず境界値で動きを確かめます。範囲の切れ目にあたる時刻を全部並べて、期待どおりかを 1 つずつ見ていきます。

時刻通る枝戻り値
0else"こんばんは"
4else"こんばんは"
51 つ目"おはようございます"
111 つ目"おはようございます"
122 つ目"こんにちは"
172 つ目"こんにちは"
18else"こんばんは"
23else"こんばんは"

4511121718 という 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 <= 12hour >= 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 つの枝に必ず入ることを、023 を手で流して確かめてください。

要件

  1. 関数名は greetByHour、引数は 0 から 23 の整数 hour の 1 つ
  2. 5 以上 12 未満なら "おはようございます"、12 以上 18 未満なら "こんにちは" を返す
  3. それ以外の時刻はすべて else で受け止め、"こんばんは" を返す
  4. 範囲の判定は && で 2 つの比較をつなぎ、戻り値はすべて文字列にする

入出力例

greetByHour(0)"こんばんは" greetByHour(5)"おはようございます" greetByHour(12)"こんにちは" greetByHour(18)"こんばんは" greetByHour(23)"こんばんは"

ヒント

main.js
main.js
学習モード

メモ

つくる 時間帯で挨拶を変える

⌘S で保存