いつもお世話になっております。
javascript初心者です。
現在、3と3の倍数になったときに「AHO!」と叫ぶプログラミングを作成しております。
やりたいことは至ってシンプルでブラウザ上で1ずつカウントアップされていく中で
3と6と9に到達したときに「AHO!」と表示させたいです。
3と6と9に到達したときにイベント起こす為に条件分岐作成したのですが、上手く作動していないのが現状です。
ご教示の程、宜しくお願いします。
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>3と3の倍数はアホと叫ぶ</title> <script type="text/javascript"> var suuji = ["1","2","3","4","5","6","7","8","9","10"]; var aaa = 0; var bbb = setInterval(start, 1000); function start() { if (aaa < 10) { document.write(suuji[aaa] + " "); aaa++; }else{ clearInterval(bbb); // タイマー停止 document.write("AHO!"); } } </script> </body> </html>
試してみたこと①
var aaa = 0;の部分を3/0にしてみるも「AHO!」としか表示されず。
試したこと②
if (aaa < 10) { document.write(suuji[aaa] + " "); aaa++; }else if(aaa == 3){ document.write("AHO!"); }else{ clearInterval(bbb); } 3に到達したときにイベント起こすように条件分岐追加してみるも動きが停止してしまいました。
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
回答5件
0
ベストアンサー
まず、今回の質問文の改良点的な所が幾つか見受けられます。
- document.writeは非推奨なのでやめよう
- 数字がアホになるか否かの判定ロジックは関数として切り分けよう
- 数字を入れるとアホ、もしくは数字を返すロジックも関数として切り分けよう
- タイマー機能を改良しよう
document.writeは非推奨なのでやめよう
document.writeはJavaScript(以下JS)黎明期の書き方ですが、
これは様々な箇所で不具合が出るダメな子です。
結果、どのJSの書籍でも「document.write」は使うな!と明記される程嫌われている機能なので忘れてください。
DOMツリー構造を動的に変更するやり方を覚えましょう。
jQueryというライブラリを扱うのが初心者にはオススメです。
jQueryのDOMを挿入を覚えてください。
この反映は質問者さんへの課題として残しておきます。
従って、今回の回答文ではconsole.log
とデベロッパーツールによる簡易的な表示方法を利用していきます。
F12キーを押すと、デベロッパーツールが立ち上がります。
console.log(123)
という風に実行すると、デベロッパーツールのconsoleタブに結果を出力してくれます。
数字がアホになるか否かの判定ロジックは関数として切り分けよう
3の倍数でアホになる判定ロジックは関数として外部に切り出してください。
関数にしてしまえば、結果の確認がとても楽になりますよ。
isナベアツ
です!
numという数値の引数を要求しており、アホになりそうだったらtrue
普通の回答で数字を教えてくれそうならfalse
になります。
JavaScript
1var isNabeatsu = function (num) { 2 return num % 3 === 0; 3} 4console.log(isNabeatsu(1)); // false 5console.log(isNabeatsu(2)); // false 6console.log(isNabeatsu(3)); // true 7console.log(isNabeatsu(4)); // false 8console.log(isNabeatsu(5)); // false 9console.log(isNabeatsu(6)); // true
よしよし、うまく動作しているようですね。
ですが、これはまだ3の倍数だけで判定するので、肝心の13や23等で反応しなさそうです。
JavaScript
1var isNabeatsu = function (num) { 2 return num % 3 === 0; 3} 4console.log(isNabeatsu(13)); // false 5console.log(isNabeatsu(23)); // false 6console.log(isNabeatsu(31)); // false
あらら、全滅です…
では、これを改良して完成させましょうか。
「数字の3が含まれている場合はfalseではなくtrueになる」が条件です。
この数字の3を探す…といった風な用途は「文字列検索」といいます。
JSには数値型や文字列型、配列、オブジェクト…など、様々な型が存在します。
それらの型には値を加工するのに使う便利な機能(メソッド)が用意されています。
先程3の倍数か否かを確認する為に、num % 3
と入力しましたね。
数値型は数値計算に利用される型であり、他の型では数値計算は不可能です。
でも数字の3を探したい……こういう要望は文字列型が得意とする仕事なので数値型から文字列型へ変換(キャスト)する必要があります。
プログラマのテクニックの一つとして、数値として判断出来る値は基本的には数値型として所持しておき、
文字列検索がしたくなったらその時だけ、文字列型にキャストする使い方が分かりやすくオススメです。
今回はString.prototype.matchを利用することにしました。
正規表現を使って文字列を探す少々高難度の手法ですが、3という文字列を探すだけの正規表現は/3/
とわりと簡単なので採用しました。
(他にも様々な方法で解決することが可能で、10人に頼めば10人共がちょっとずつ違う判定ロジックを持ってくると思います。探してみてね!!)
JavaScript
1// 文字列検索を行うmatchメソッドは文字列型限定のメソッド 2var num = 123; 3num.match(/3/); 4// Uncaught TypeError: num.match is not a function 5 6// JSでは.toString()を使えば全ての値が文字列型にキャストされる 7num.toString().match(/3/); 8// ["3", index: 2, input: "123", groups: undefined] 9 10// 値をカッコで包んだりしてそのまま.toString()で文字列型にして使うことも可能 11(17).toString().match(/3/); 12// null 13 14// 論理型にキャストするにはBooleanを使う 15Boolean((31).toString().match(/3/)); 16// true 17Boolean((16).toString().match(/3/)); 18// false
これを元にisナベアツ
関数を完成させましょう。
「3で割り切れる数字」もしくは「数字の3がある」場合ですので、
論理和であるor演算子||
を利用します。
JavaScript
1var isNabeatsu = function (num) { 2 return (num % 3 === 0) || Boolean(num.toString().match(/3/)); 3} 4console.log(isNabeatsu(1)); // false 5console.log(isNabeatsu(2)); // false 6console.log(isNabeatsu(3)); // true 7console.log(isNabeatsu(13)); // true 8console.log(isNabeatsu(23)); // true 9console.log(isNabeatsu(31)); // true 10console.log(isNabeatsu(25)); // false
いい感じに動作してますね。
isナベアツ関数完成です。
数字を入れるとアホ、もしくは数字を返すロジックも関数として切り分けよう
今度はtoナベアツ
関数を作成しましょうか。
これも切り分ける事でテストが非常にしやすくなります。
もうアホになるべき数字か否かを判定する関数は出来ていますね?
今回は「特定条件でAHO!」か「そうでなければ数字をそのまま使う」ので、三項演算子を使ってみましょうか。
ついでに、AHO!
という文字列が返ってくる可能性がある以上、もう片方の数字も文字列型にキャストして同じ文字列型に合わせておいたほうが使いやすそうですね。
JavaScript
1var isNabeatsu = function (num) { 2 return (num % 3 === 0) || Boolean(num.toString().match(/3/)); 3} 4var toNabeatsu = function (num) { 5 return isNabeatsu(num) ? 'AHO!' : num.toString(); 6} 7console.log(toNabeatsu(1)); // 1 8console.log(toNabeatsu(2)); // 2 9console.log(toNabeatsu(3)); // AHO! 10console.log(toNabeatsu(13)); // AHO! 11console.log(toNabeatsu(23)); // AHO! 12console.log(toNabeatsu(31)); // AHO!
はい完了。
このように同じ数字を入れると、必ず同じ値が返ってくるような処理は関数化しておくと、
このように動作確認が楽ですね。
早速これを質問文に組み込みましょう。
suuji変数に入っている配列を全て消化したら完了というロジックに変更しています。
JavaScript
1var isNabeatsu = function (num) { 2 return (num % 3 === 0) || Boolean(num.toString().match(/3/)); 3} 4var toNabeatsu = function (num) { 5 return isNabeatsu(num) ? 'AHO!' : num.toString(); 6} 7var suuji = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; 8var aaa = 0; 9var bbb = setInterval(start, 1000); 10 11function start() { 12 // 表示したい文字列は今回はconsole.logを使って表示 13 console.log(toNabeatsu(suuji[aaa])); 14 aaa++; 15 if (aaa >= suuji.length) { 16 clearInterval(bbb); // タイマー停止 17 } 18} 19// 1 20// 2 21// AHO! 22// 4 23// 5 24// AHO! 25// 7 26// 8 27// AHO! 28// 10
1秒おきにconsole.logが実行されて、表示されていく様が分かります。
10秒後に数字の値が全て表示されて、これで完了ですね。
【おまけ】
タイマー機能を改良しよう
見事動くようになりましたが、
関数はともかく、このsuuji
、aaa
、bbb
がキモいんですよねぇ……
何がキモいって、start関数の中から決め打ちで読みにいってるあたりです。
こういう変数は「状態変数」といって、
出来るだけ減らした方がかっこいいのです。
そのためのテクニックはいくつかありますが、今回は2つ加えます。
- ループの仕組みをsetTimeoutを使った再起ループ化
- start関数は引数の配列を監視して続けるかやめるか選ぶように
JavaScript
1var isNabeatsu = function (num) { 2 return (num % 3 === 0) || Boolean(num.toString().match(/3/)); 3} 4var toNabeatsu = function (num) { 5 return isNabeatsu(num) ? 'AHO!' : num.toString(); 6} 7var start = function (numbers) { 8 if (numbers[0] == null) return; 9 console.log(toNabeatsu(numbers[0])); 10 setTimeout(start.bind(null, numbers.slice(1)), 1000); 11} 12start([1, 2, 3, 4, 5, 6, 7, 8, 9, 10,]); 13// 1 14// 2 15// AHO! 16// 4 17// 5 18// AHO! 19// 7 20// 8 21// AHO! 22// 10
全ての関数にはfunction.prototype.bindというメソッドが用意されています。
まぁ、要するに関数に値を適用しつつ、実行しないで待ってくれるという必殺技があるんです。
JavaScript
1var add = function (a, b) { return a + b; } 2add(2, 3); 3// 5 4 5var add10 = add.bind(null, 10); 6add10(5); 7// 15
更に配列にはarray.prototype.sliceという配列の一部を切り出すメソッドがあります。
これを利用して金太郎アメのようにnumbers変数の関数を頭から1個ずつ削り取って利用する作りにしています。
JavaScript
1[1, 2, 3].slice(1) 2// [2, 3] 3 4[1, 2, 3].slice(1).slice(1) 5// [3]
全体的な流れとしてはこうです。
[1, 2, 3 ...]
という配列がnumbersに入って実行- 先頭の1を取り出す
[1, 2, 3 ...].slice(1)
を実行して、得た結果[2, 3 ...]
を次のstartに格納しておく- 1秒後、次のstartが実行、今度は先頭の2を取り出す
- これを繰り返し、最終的に空の配列
[]
を次のstartに格納 - 1秒後、次のstartが実行、先頭のアイテムが無いので終了
投稿2018/03/18 14:58
編集2018/03/19 16:38総合スコア21145
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2018/03/18 16:04 編集
2018/03/18 16:09
2018/03/18 23:37
2018/03/19 01:30
2018/03/19 16:50
2018/03/20 02:31
2018/03/20 15:29
2018/03/21 02:51
2018/03/22 00:39
2018/03/22 04:42
2018/03/22 05:09
0
例えばこんな
HTML
1<output id="out" style="white-space:pre;"></output> 2<script> 3"use strict"; 4{ 5 let i = 0; 6 const max = 100, h = setInterval(() => { 7 let result = ++i % 3 == 0 || i.toString().match(/3/) ? "aho!" : i; 8 out.value += `${result}\n\r`; 9 if(i >= max){ 10 clearInterval(h); 11 } 12 }, 1000); 13} 14</script>
NOTE:
当初はdocument.write
を使っていましたが, FireFoxにおいてsetInterval
による非同期処理と相性が悪かったため, 出力先を変更しています.
投稿2018/03/18 13:31
編集2018/03/18 15:34総合スコア4756
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2018/03/18 13:51
2018/03/18 13:53
2018/03/18 15:13
2018/03/18 15:32
2018/03/18 15:48
0
余計なお世話かもしれませんが、文字列比較を使わないバージョンも載せておきます。
ご参考にしてください。
html
1<!doctype html> 2<html> 3 <head> 4 <meta charset="utf-8"> 5 <title></title> 6 <script type="text/javascript"> 7window.onload = function() { 8 function aho(x) { 9 if (x % 3 == 0) 10 return true; 11 while (x > 0) { 12 if (x % 10 == 3) 13 return true; 14 x = Math.floor(x / 10); 15 } 16 return false; 17 } 18 var p = document.getElementById('number'); 19 var x = 1; 20 function update() { 21 p.innerHTML += aho(x) ? 'AHO!' : x; 22 p.innerHTML += '<br>'; 23 x++; 24 } 25 setInterval(update, 100); 26}; 27 </script> 28 </head> 29 <body> 30 <p id="number"></p> 31 </body> 32</html>
投稿2018/03/20 13:43
退会済みユーザー
総合スコア0
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
javascript
1 2for (var i = 1; i < 11) { 3 if (i % 3 === 0) { 4 document.write("AHO!"); 5 } else { 6 document.write(i); 7 } 8}
投稿2018/03/18 13:21
退会済みユーザー
総合スコア0
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2018/03/18 13:53 編集
退会済みユーザー
2018/03/18 15:35 編集
2018/03/18 16:27 編集
2018/03/18 22:06
2018/03/20 04:19
退会済みユーザー
2018/07/11 08:53
0
注: document.write は文書ストリームに書き込みを行うため、閉じられた(ロード済みの)文書で document.write を呼び出すと、自動的に document.open が呼ばれ、文書はクリアされます。
投稿2018/03/19 01:59
総合スコア35813
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。