何が間違っている? JavaScript のトラブルシューティング① (構文エラー、論理エラー)
MDN( https://developer.mozilla.org/ja/docs/Web/JavaScript )
を参考に勉強するように注意が入ったので、こらを教本にしていきます。
その為、抜粋しながら進めたいと思います。
今回はこちらです。
エラーの種類
コードに誤りがある場合、一般的に以下の2つのうち、どちらかの誤りであることがよくあります。
- 構文エラー: プログラムが全く動かなかったり、途中で止まったりするような記述エラーで、通常はエラーメッセージが出力されます。正しいツールに慣れて、エラーメッセージの内容がわかるのなら、さほど無理なく修正が可能です。
- 論理エラー: 書き方は正しくても、コードが意図した通りに動ないエラーです。つまりプログラムは動くのですが、間違った結果を返します。たいていの場合に、問題となる箇所に直接のエラーメッセージが出ることがないため、構文エラーよりも直すのが難しいことが多いです。
「文字の打ち間違い」も構文エラーに入ります。
例えば「title」と打とうとして「tittle」にしたこともあります(笑)
これは一番修正しやすいですが、見落としやすいので気をつけてください。
構文エラー
エラー参考にこちら 1)を記載してくれています。
構文エラーを修正①
エラー参考を開き、早速ゲームを始めます。
予想を入力し”予想を投稿”ボタンを押しても・・・動きません。
コンソールにはこのようなエラーが表示されました。
エラーメッセージ
日本語にすると『guessSubmit.addeventListenerは関数ではありません。』
(JavaScriptインタープリターに呼び出している関数が認識されないという意味)
簡単に言ったら、スペルミスをしたということです。
グレーの部分「sample.html?_ijt=vs00tkdvk9ftb5dmh1n464d4ed&_ij_reload=RELOAD_ON_SAVE:86:15」を押してみるとこの画面が表示されました。
テキストエディターで86行目を見てみると・・・。
guessSubmit.addeventListener('click', checkGuess);
正しくはこちらです。
guessSubmit.addEventListener('click', checkGuess);
修正するとコンソールにエラーがなくなりました。
構文エラーを修正②
予想を入力し”予想を投稿”ボタンを押してみると...別のエラーが発生しています。
エラーメッセージ
日本語にすると『nullのプロパティ「textContent」を設定できません。』
1. nullは?
グレーの部分「sample.html?_ijt=vs00tkdvk9ftb5dmh1n464d4ed&_ij_reload=RELOAD_ON_SAVE:78」を押してみるとこの画面が表示されました。
テキストエディターで78行目を見てみると・・・。
lowOrHi.textContent = 'Last guess was too high!';
lowOrHi定数のtextContentプロパティに文字列を設定しようとしていますが、lowOrHi定数に適切な値が設定されていないため上手く動いていません。
lowOrHiが使用されている箇所をコードのほかの部分から探します。
lowOrHiが使用されている箇所
49行目 const lowOrHi = document.querySelector('lowOrHi');
67行目 lowOrHi.textContent = '';
76行目 lowOrHi.textContent = 'Last guess was too low!';
78行目 lowOrHi.textContent = 'Last guess was too high!';
今回は「.textContent」が使用されていない49行目ですね。
const lowOrHi = document.querySelector('lowOrHi');
こちらは段落に値を追加するために使用している部分です。
HTMLの要素を参照する変数を作ろうとしています。
この行の後ろで、値がnullになっているか確認するため以下のコードを直後の50行目に追加します。
console.log(lowOrHi);
コンソールを見てみると「null」と表示されています。
lowOrHi
の値はnull
とわかりました。
2. 何が問題?
49行目では要素への参照をCSSセレクターを使用して取得する document.querySelector()
メソッドが使用されています。
ファイルの少し上のほうにある、問題となる<p>要素を見てみます。
<p class="lowOrHi"></p>
ここではクラスセレクター[1]が必要です。
クラスセレクターはドット(.)で始まりますが、 9行目querySelector()
メソッドに渡された文字列にはドットがありません。
49行目のlowOrHi
を「.lowOrHi」に変更してみます。
再度読み込むとコンソールはこちらの表示になりました。
エラーを潰すことができました。
console.log()
の行は削除してもいいですし、後で使うために残しておいても大丈夫です。
構文エラーを修正③
ゲームを進めていくと...正解するか、ゲームーオーバーになるとエラーが発生しました。
エラーメッセージ
日本語にすると『resetButton.addeventListenerは関数ではありません』
グレーの部分が今回2種類あります。
「sample.html?_ijt=vs00tkdvk9ftb5dmh1n464d4ed&_ij_reload=RELOAD_ON_SAVE:95:17」を押してみるとこの画面が表示されました。
「sample.html?_ijt=vs00tkdvk9ftb5dmh1n464d4ed&_ij_reload=RELOAD_ON_SAVE:72:7」を押してみるとこの画面が表示されました。
テキストエディターで95行目を見てみると・・・。
resetButton.addeventListener('click', resetGame);
構文エラー①と同じ間違えをしています。
正しくはこちらです。
resetButton.addEventListener('click', resetGame);
修正するとコンソールにエラーがなくなりました。
論理エラー
ゲームを進めていくと...予想すべきランダムな数字が常に「1」になっていることに気づくと思います。
コンソールにはエラーは表示されていません。
エラーにはなっていませんが、ゲームのロジック(思考の道筋)に問題が生じています。
1.常に1しか表示されない原因は?!
randomNumber
変数にランダムな数値が最初にセットされる場所を検索してみます。
ゲームの開始で推測するランダムな数字を保存しようとしているのは45行目のあたりです。
(1から100までのランダムな数字が代入)
let randomNumber = Math.floor(Math.random()) + 1;
そして、それぞれのゲームの合間に次のランダムな数字を設定しているのは116行目のあたりです。
(同じ数字以外の数字でゲームができるように、新しいランダムな数字を再度生成)
randomNumber = Math.floor(Math.random()) + 1;
これらの行が問題となるかを確認するため、console.log()
を使用します。
先ほどのそれぞれの行の直下に以下のコードを追加します。
console.log(randomNumber);
コンソールに出力されるrandomNumber
の値が常に「1」です。
これを直すためにはこの行が何をしているか知らなければいけません。
まずMath.random()
を見てみます。
これは0〜1までのランダムな実数値を生成します。
Math.random()
ちゃんと0〜1で反応をしています。
次に、この実行結果をMath.floor()
に渡して、一番近い整数に切り捨てます。
そしてその結果に1を加えます。
Math.floor(Math.random()) + 1
0から1のランダムな実数を切り捨てると、結果は常に「0」になり、それに1を加えることで常に「1」となります。
そのため、「1」が表示されていたのです。
2. 0〜100にするため
ランダムな数を一番近い整数に切り捨てる前に「100」を乗算しなければなりません。
Math.floor(Math.random()*100);
こちらのコードだと0〜99までのランダムな数値しか生成されません。
さらに「1」を加えることで、1〜100のランダムな数字を返してくれるようになります。
先ほどの2行(45行目のあたり、116行目のあたり)をそれぞれ修正し、保存して再度読み込むと、思い通りに動くようになっています。
文献表
- github「mdn/learning-area」のnumber-game-errors.htmlに記載
https://github.com/mdn/learning-area/blob/main/javascript/introduction-to-js-1/troubleshooting/number-game-errors.html
(2023/03/28閲覧)
-
クラスセレクター(classセレクター)
class属性によって特定のclass名がつけられた要素を対象にスタイルを適用するセレクターです。
class属性は1つの文書内で同じclass名を重複して指定することができます。 classセレクタを使用することで、文書内の複数箇所や異なる要素に対して同じスタイルを適用することができます。
書式 :.クラス名 {プロパティ名:値;}
適用対象:クラス名を付けた要素
↩︎
Discussion