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

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

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

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

ループ

ループとは、プログラミングにおいて、条件に合致している間、複数回繰り返し実行される箇所や、その制御構造を指します

Q&A

解決済

3回答

944閲覧

ループ処理がうまくいかない、functionのreturnの使い方がわからない

saknfsh

総合スコア1

JavaScript

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

ループ

ループとは、プログラミングにおいて、条件に合致している間、複数回繰り返し実行される箇所や、その制御構造を指します

0グッド

1クリップ

投稿2022/01/06 01:31

編集2022/01/06 01:35

前提・実現したいこと

JavaScriptで、
window.prompt()
に入力された値から計算を行い、HTML上で1秒ごとに1秒減っていくカウントダウンタイマーを制作しようとしています。
しかし、functionの設計が甘いのか(returnがいまいちよくわかっていない。)、わかりませんが、うまくループできない&そもそも計算をしていないという現象に陥っています。
function countdown()内の、return recalcでsecondに代入し(ここのやり方がわからない)、function refreshでsecondの値を1減らし...といったループができることを想定していました。

どこが原因でプログラムが動いていないのでしょうか。何度も見直しましたが、初心者故、結局わからずじまいで…
ご教授いただけたら幸いです。
ここのサイトを使うのは初めてかつ、人にプログラムを見てもらう、方法を尋ねるというのは初めてなので、拙い部分があったらごめんなさい。

該当のソースコード

javascript

1 let minute = parseInt(window.prompt('何分測りますか'));  //測りたい分数を入力 2 let second = minute * 60; //秒単位にする 3 4 function countdown(){ 5 let recalc = minute; 6 let min = Math.floor(recalc / 60); //分に直す 7 let sec = Math.floor(recalc / 60 * 10); //余りを用いて秒に直す 8 document.getElementById('min').textContent = 'min' ; //HTMLに分として表示 9 document.getElementById('sec').textContent = 'sec' ; //HTMLに秒として表示 10 console.log(minute); 11 return recalc; //returnでsecondに再代入したいが、代入する方法がわからない。多分これのせいでプログラムが動かない。 12 } 13 14 function refresh(){ 15 second -= 1; //秒のカウントを1減らす 16 setTimeout(countdown,1000); //1秒ごとに関数countdownを実行させる 17 } 18 19 while (second <= 0){ 20 refresh(); //0秒になるまで続ける 21 } 22 23 window.alert('終了')

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

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

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

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

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

guest

回答3

0

ベストアンサー

うまくループできない&そもそも計算をしていない

js

1 while (second <= 0){ 2 refresh(); //0秒になるまで続ける 3 }

ここで while の条件が「secondが0以下なら繰り返し」となっているので、second が0より大きいと一度も refresh() が呼ばれません。


js

1 function refresh(){ 2 second -= 1; //秒のカウントを1減らす 3 setTimeout(countdown,1000); //1秒ごとに関数countdownを実行させる 4 }

setTimeout(countdown, 1000) は、countdown() を約1秒後に実行することを予約するだけで、countdown() の実行終了を待ちません。関数 refresh()countdown() が実行されるより前に終了します。


現在のコードをできるだけ尊重するなら、以下のような感じになるでしょうか。

js

1let minute = parseInt(window.prompt('何分測りますか'));  //測りたい分数を入力 2let second = minute * 60; //秒単位にする 3if (second > 0) 4 setTimeout(countdown, 1000); 5 6function countdown(){ 7 second -= 1; 8 let min = Math.floor(second / 60); //分に直す 9 let sec = second % 60; //余りを用いて秒に直す 10 document.getElementById('min').textContent = min ; //HTMLに分として表示 11 document.getElementById('sec').textContent = sec ; //HTMLに秒として表示 12 if (second > 0) 13 setTimeout(countdown, 1000); 14 else 15 window.alert('終了'); 16}

yambejpさんも書いてますが、setTimeout()はそんなに正確な時間で呼び出すわけではないので、正確にやるなら開始時刻と現在時刻の差をチェックするほうがよいです。

投稿2022/01/06 04:19

編集2022/01/06 04:19
int32_t

総合スコア21695

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

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

saknfsh

2022/01/08 00:50

私が今回躓いた点や打開策など、細かくまとめて下さりありがとうございます。そもそもが初歩的なミスでしたね...functionの中にifを設けるのは考えが及ばなかったので、今後参考にさせていただこうと思います。 すごくすごく助かりました。ありがとうございました。m(_ _)m
guest

0

jsでwhileループは同期処理なのでこの手の処理には向いていないかもしれません。
setIntervalなどでpromiseを利用してasync/awaitすると良いでしょう
またカウントダウン処理は時計を利用するようにしてください

javascript

1<script> 2window.addEventListener('DOMContentLoaded', ()=>{ 3 let timerId; 4 document.querySelector('#start').addEventListener('click',async()=>{ 5 clearInterval(timerId); 6 let minute = parseInt(prompt('何分測りますか')); 7 let second = minute * 60; 8 const endtime=new Date().getTime()+minute*60*1000; 9 await new Promise(resolve=>{ 10 timerId=setInterval(()=>{ 11 const t=new Date().getTime(); 12 if(t>=endtime){ 13 clearInterval(timerId); 14 resolve(); 15 } 16 second=parseInt((endtime-t)/1000); 17 countdown(second); 18 },100); 19 }); 20 window.alert('終了'); 21 }); 22}); 23const countdown=s=>{ 24 let min = Math.floor(s / 60); //分に直す 25 let sec = Math.floor(s % 60); //余りを用いて秒に直す 26 document.getElementById('min').textContent = min; 27 document.getElementById('sec').textContent = sec; 28} 29</script> 30<input type="button" value="start" id="start"> 31<span id="min"></span>32<span id="sec"></span>

投稿2022/01/06 02:16

編集2022/01/06 02:24
yambejp

総合スコア116724

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

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

saknfsh

2022/01/06 03:52

ありがとうございます。使っている参考書が古いのかわかりませんが、参考書で用いられているコードをチラ見しながら書いたプログラムでしたので... 読んでて初めてみる書き方とかオブジェクトがあったので、yambejpさんが書いてくださったコードを元に更に勉強してみようと思います。 僭越ながら、私が書いたコードがなぜ動かないのかも教えていただければ幸いです。やはりreturnでsecondに代入が出いていないからでしょうか。
yambejp

2022/01/06 03:59

> なぜ動かないのか ちょっと「ここです」と指摘できるような単純なミスではなく、そもそもが無理筋な書き方をしている感じです。 私の全体の流れは、分数を決めた時点で最終時間を設定して、そこに至るまで0.1秒単位で問い合わせをしています。質問者さんのソースだとrefreshも何をしたいかわからないですし、whileも不適切です。setTimeoutを利用するならwhileではなく、コールバックの中で再度自分を呼び続ける必要があります。
guest

0

どこが原因でプログラムが動いていないのでしょうか。

考え方です。
おそらく質問者さんは、whileループ内で表示更新して1秒待つ動作を繰り返し実行して最後にalert('終了')を実行したいのだと思いますが、JavaScriptに「処理中に1秒待つ」という命令は存在しないのでそのようなコードは基本的に書けません。
setTimeout(countdown,1000);は1000ミリ後にcountdown関数の実行を予約して即座に次の行以降の実行を行うという命令なので「処理中に1秒待つ」ことはできません。

ちなみに、Promiseとasync/awaitを使えば擬似的に「処理中に1秒待つ」ようなコードは書けますが、内容を理解せずに使うのはおすすめしません。

1秒ごとに何かをする単純なサンプルとして、1秒ごとにconsole.logで数字を表示するという例を示します。

javascript

1// setTimeoutを使った書き方 2// 初学者にも仕組みを理解できると思います 3 4let count = 5; 5 6function countdown(){ 7 count -= 1; 8 console.log(count); 9 if (count > 0) { 10 setTimeout(countdown, 1000); 11 } 12} 13 14setTimeout(countdown, 1000); 15 16 17// async/awaitを使った書き方 18// こっちのほうが直感的に見えるコードですが、 19// 意味を理解せずに使うと意味が理解できない問題にぶち当たると思います 20 21(async () => { 22 const sleep = ms => new Promise(resolve => setTimeout(resolve, ms)); 23 24 let count = 5; 25 26 while (count > 0) { 27 count -= 1; 28 console.log(count); 29 await sleep(1000); 30 } 31})();

投稿2022/01/06 05:52

ku__ra__ge

総合スコア4524

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

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

saknfsh

2022/01/08 00:44

ありがとうございます。setTimeoutはそのような動作をするのですね。setTimeoutを使ったコードは理解できましたが(そっかfunctionの中にifを組み込んでしまえばよかったのか...)、Promiseとasync/awaitに関しては今回の質問で初めて見たオブジェクトなので、今後勉強していこうと思います。ご回答ありがとうございました。m(_ _)m
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問