質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
Chrome

Google Chromeは携帯、テレビ、デスクトップなどの様々なプラットフォームで利用できるウェブブラウザです。Googleが開発したもので、Blink (レンダリングエンジン) とアプリケーションフレームワークを使用しています。

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

Chrome extension

Chrome拡張機能

Q&A

1回答

1157閲覧

if文の多いJavaScript記述からif文を減らしてスッキリさせたいけど思いつかない

moimoi_sushi

総合スコア26

Chrome

Google Chromeは携帯、テレビ、デスクトップなどの様々なプラットフォームで利用できるウェブブラウザです。Googleが開発したもので、Blink (レンダリングエンジン) とアプリケーションフレームワークを使用しています。

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

Chrome extension

Chrome拡張機能

0グッド

1クリップ

投稿2020/04/30 03:16

前提・実現したいこと

指定時間の間は、指定したアプリを開かないChrome拡張機能を作成しました。指定時間は任意で複数用意することができます。
そのアプリの中で時間判定、すなわち現在時刻は設定時刻の範囲内にあるのかどうかの処理の記述があります。

発生している問題・エラーメッセージ

その記述の書き方が結果としてif文の多いものとなってしまい腑に落ちなくなってしまいました。
getTimeの中身ですが、
{'set1' : { [12, 00], [16, 00] } }
{'set2' : { [22, 00], [1, 00] } }
...
のように、開始時刻と終了時刻の順番で配列を格納しています。

JavaScript

1function hoge(data){ 2//最初に呼び出される関数 3 const getSort = Object.keys(data).sort(( a, b ) => data[a][0] > data[b][0] ? 1 : -1); //データを開始時刻を基準に昇順で並べ替えている 4 for( let i = 0; getSort.length > i;i++ ) { 5 let getTime = data[getSort[i]]; 6 const result = timeFind(getTime); 7 (この行にあったresultがtrueだった場合にページ遷移する処理は省略しました) 8 } 9 } 10}); 11 12const timeFind = (getTime) => { 13//この関数の中でif文がたくさん出てきますがもっとシンプルに書ける気がしていますが思いつきません。 14 const today = new Date(); 15 const nowHour = today.getHours(); 16 const nowMin = today.getMinutes(); 17 const startHour = Number(getTime[0][0]); 18 const finishHour = Number(getTime[1][0]); 19 const startMin = Number(getTime[0][1]); 20 const finishMin = Number(getTime[1][1]); 21 22 const termHour = finishHour - startHour; 23 24 if(termHour < 0) { 25 // 日を跨ぐ時間の処理 26 if(nowHour > startHour || nowHour < finishHour) return true; 27 } 28 29 if(termHour > 0) { 30 if(nowHour > startHour && nowHour < finishHour) return true; 31 } 32 33 if(termHour === 0){ 34 if(nowHour === startHour && nowHour === finishHour) { 35 const result = nowMin >= startMin && nowMin <= finishMin ? true : false; 36 return result; 37 } 38 } 39 40 if(nowHour === startHour) return StartMin(startMin); 41 if(nowHour === finishHour) return FinishMin(finishMin); 42 43 function FinishMin(finishMin) { 44 const result = nowMin <= finishMin ? true : false ; 45 return result; 46 } 47 48 function StartMin(startMin) { 49 const result = nowMin >= startMin ? true : false ; 50 return result; 51 } 52//ここまで全てfalseであればfalseを返すためのreturn 53 return false; 54}

teratail投稿用にコメントをたくさん挿入しました。

試したこと

最初はif文を2,3回ほどで記述したものがあったのですが、日を跨いだり、時間判定した後に分判定を入れることを想定していなかったために思ったように動きませんでした。
それから修正バージョンも考えたのですがそれもうまく記述できず。if文をたくさん使うことにしましたがもっとスッキリさせたいです。

補足情報(FW/ツールのバージョンなど)

生JavaScript
Chrome拡張機能のローカルストレージにデータを格納

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Zuishin

2020/04/30 03:39

全部「分」に直したらどうでしょうか。
think49

2020/05/03 03:34

awakewalkerさん なぜ、Zuishinさんの指摘を無視しているのでしょうか。
moimoi_sushi

2020/05/03 05:22

>全部「分」に直したらどうでしょうか。 試してからコメントしようと思っており保留していました。
guest

回答1

0

こんにちは

以下、参考として回答します。使えそうなコードが一部でもあれば幸いです。

1. 一日の開始時刻を示す定数を定義

javascript

1// 1日の開始を 06:00 とする 2const START_HOUR_OF_DAY = 6;

上記によって、

  • ["06", "00"] は今日の朝6時を表し、
  • ["05", "59"]は翌日の午前5時59分を表す

ことになります。

2. サンプルデータ

サンプルデータとして以下のような配列 timeSets を考えます。

javascript

1// サンプルデータ 2const timeSets = [ 3 { set1: [["07", "00"], ["08", "30"]] }, 4 { set2: [["22", "45"], ["02", "00"]] }, 5 { set3: [["15", "00"], ["16", "30"]] }, 6 { set4: [["22", "00"], ["23", "30"]] }, 7 { set5: [["15", "30"], ["17", "00"]] }, 8 { set6: [["23", "00"], ["01", "00"]] }, 9 { set7: [["04", "30"], ["05", "45"]] } 10];

3. moment の使用

ある日時と別の日時との比較や、1日加えるといった処理を楽に行うために、日時を扱うのに便利なライブラリ moment を使います。(※最近では moment よりも date-fns のほうが好まれる場合もありますが、この回答では、momentを使います。)

上記の timeSets の各要素が表す開始時刻と終了時刻の間にあるかどうかを判定する時刻を含むmomentオブジェクトを入れる変数を time とします。

javascript

1// 時刻のフォーマット 2const TIME_FORMAT = "HH:mm"; 3 4// 比較対象となる時刻 5const time = moment("23:15",TIME_FORMAT);

4. 判定するコード

timeSetsの要素の中で、time が開始と終了の間にある(両端も含む)もののキーを表示するコードは以下のように書けます。

javascript

1// hour が 日付の変わる時刻未満であれば、日付を1日加算する。 2if (time.hour() < START_HOUR_OF_DAY) { 3 time.add(1, 'day'); 4} 5 6// timeSetsの要素の中で、time が開始と終了の間にある(両端も含む)ときのキーを表示 7timeSets.forEach(set => { 8 const [[key, [startAry, endAry]]] = Object.entries(set); 9 10 const start = moment(`${startAry.join(":")}`, TIME_FORMAT), 11 end = moment(`${endAry.join(":")}`, TIME_FORMAT); 12 13 // hour が 日付の変わる時刻未満であれば、日付を1日加算する。 14 if (start.hour() < START_HOUR_OF_DAY) { 15 start.add(1, 'day'); 16 } 17 if (end.hour() < START_HOUR_OF_DAY) { 18 end.add(1, 'day'); 19 } 20 21 // time が、start以上、end以下であれば、オブジェクトのキーを表示 22 if (start.isSameOrBefore(time) && end.isSameOrAfter(time)) { 23 console.log(key); 24 } 25}); 26 27

上記を実行すると

"set2"

"set4"
"set6"

と表示されます。 以下は上記のコードをCodePenに写したものです。

上記のサンプルで、比較対象となる時刻 time

javascript

1const time = moment("05:00",TIME_FORMAT);

に変更すると、該当するtimeSetsの要素として、

"set7"

だけが表示されます。

以上、参考になれば幸いです。

追記

上記のサンプル1を、リファクタリングしたコードを挙げておきます。

これは、サンプル1を以下の2点

  • moment のプラグインで、2つの日時による幅を表すオブジェクトを作ることのできる moment-range を使用し、これの containsメソッドを、時間帯の範囲内かどうかの判定に利用

    

  • 時刻を表す、文字列の配列(["07", "00"]["01", "00"]など) から、この配列の示す時刻を含む momentオブジェクトを作る関数を momentFromHHMM として、forEach ループから切り出す。

によってリファクタして、forEachループ本体のコード行数を減らしたものです。

追記2

回答した当初、サンプルコードや回答の文章の中で、変数名やプロパティ名の一部に "step" を使っていましたが、ご質問にある以下

{'set1' : { [12, 00], [16, 00] } } {'set2' : { [22, 00], [1, 00] } }

にあわせて、"set" に修正しました。

投稿2020/04/30 07:21

編集2020/05/03 23:52
jun68ykt

総合スコア9058

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

moimoi_sushi

2020/05/01 09:33 編集

サンプルまでありがとうございます。 参考にしながら当てはめて動かしてみました 試しに日付の変わる const date = moment("2020-05-01 06:00:00") に時間を設定し START_HOUR_OF_DAY = 6 のままで、 ①5:00 ~ 7:00 と ②7:00 ~ 6:00 の2つの日付を跨ぐパターンを当てはめてみた所、判定が出ませんでした。 if (start.hour() < START_HOUR_OF_DAY) { start.add(1, 'day'); } if (end.hour() < START_HOUR_OF_DAY) { end.add(1, 'day'); } ここの所で上手くいっていないのかなと。 自分で良い感じにアレンジしようと試みたのですが良い感じにできず。6時を1日の始まりとするのは不等号を使うためで良かったのでしょうか。
jun68ykt

2020/05/02 01:56

@awakewalkerさん コメントありがとうございます。 まず、お知らせですが、回答に挙げたサンプル https://codepen.io/jun68ykt/pen/QWjMVmJ?editors=0012 を一部修正しました。 修正前は、回答を書いた4月30日でしか正しく結果が得られないコードだったのを修正しました。また、サンプルの修正に合わせて、回答の文章も修正、追加しました。 次に頂いたコメントにある > ①5:00 ~ 7:00 と ②7:00 ~ 6:00 の2つの日付を跨ぐパターンを当てはめてみた所、判定が出ませんでした。 との件について回答します。 まず前提として回答に挙げているコードでは moment を使っており、判定対象の time 、および steps の各要素に入っている配列データも、ともに時刻が与えられており日付は無いのですが、プログラムの中で const time = moment("23:15",TIME_FORMAT); であったり const start = moment(`${startAry.join(":")}`, TIME_FORMAT), end = moment(`${endAry.join(":")}`, TIME_FORMAT); によって作られる、 time , start , end は、時刻だけではなく日付も持っています。そのうえで const START_HOUR_OF_DAY = 6; によって、1日の開始を 06:00 とするという取り決めを導入したことによって ①5:00 ~ 7:00 は、 ・開始日時が明日の05:00 ・終了日時が今日の07:00 という範囲を表すことになり、このような範囲にある日時は存在しないので、 if (start.isSameOrBefore(time) && end.isSameOrAfter(time)) { の if に与えている条件式は、常に false になります。 ②7:00 ~ 6:00 は、7:00 および 6:00 がともに今日の時刻を表すものとして扱われるので、 ・開始日時が今日の07:00 ・終了日時が今日の06:00 という範囲を表すことになり、①と同様に、このような範囲にある日時は存在しないので、 if (start.isSameOrBefore(time) && end.isSameOrAfter(time)) { の if に与えている条件式は、常に false になります。 上記をふまえて、この後のawakewalkerさんの作業として、与えられる time としていくつかのサンプルと、stepsの要素としてもいくつかのサンプルを用意して、 いくつかのtime と いくつかのsteps要素の組み合わせに対し、時間帯の範囲内にある、またはない、と判定される期待値を整理することかなと思います。 その整理によって要件がはっきりすると思いますので、その要件しだいでは const START_HOUR_OF_DAY = 6; というように、(0時以外の)一日の始まりを導入すること自体があまり適していないという判断になるかもしれません。 要件の整理後、新たにコードを書くときに、回答に挙げたサンプルコードのどこか一部でもお役に立てれば幸いです。
jun68ykt

2020/05/02 03:11

補足 ひとつ、ここを詰めると要件がはっきりする、と思われる点を補足しておきます。 ご質問にあるコードに {'set2' : { [22, 00], [1, 00] } } という要素があります。この set2 の値である [22, 00], [1, 00] という配列は何を表することにするのか?という点です。考えられる可能性として、(少なくとも)以下の(1),(2) の2とおりの解釈が可能です。 (1) 開始時刻がある日の 22:00 で、終了時刻が同じ日の 1:00 であることを表す この場合、ある同じ一日の 22時に始まり、1時に終わるという時間帯は、開始時刻が終了時刻よりも後なので、このような時間帯に含まれる時刻は存在しないことになります。 または、 (2) 開始時刻がある日の 22:00 で、終了時刻がその翌日の 1:00 であることを表す この場合、そのような時間帯はあり得ます。時間帯の幅として3時間あり、この幅の中にある時刻は、判定のプログラムによって、開始と終了の範囲内にあると判定されなければなりません。 以上のとおり、  [22, 00], [1, 00]  の解釈を上記の (1)または(2) のどちらにするのか?も要件を決める上での、重要な観点かなと思われました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問