前の記事の「数字当てゲーム」を作っていて、動かないことはありませんでしたか?恐れることはありません。この記事では、そんな心配をしなくて済むように、JavaScript のエラーを見つけて直す方法を伝授します。

前提条件: 基本的なコンピューターリテラシー、HTML および CSS の基本的な理解、JavaScript が何かの理解。
目的: コード内のシンプルな問題を修正し始める能力と自信を得る。

エラーの種類

コードに誤りがある場合、一般的に以下の 2 つのうち、どちらかの誤りであることがよくあります。

  • 文法エラー: プログラムが全く動かなかったり、途中で止まったりするような記述エラーで、通常はエラーメッセージが出力されます。正しいツールに慣れて、エラーメッセージの内容がわかるのなら、さほど無理なく修正が可能です。
  • 論理のエラー: 書き方は正しくても、コードが意図した通りに動ないエラーです。つまりプログラムは動くのですが、間違った結果を返します。たいていの場合に、問題となる箇所に直接のエラーメッセージが出ることがないため、文法エラーよりも直すのが難しいことが多いです。

まあ、こんなに単純ではありません。もっと深く追及していくと違う種類のエラーも出てくることでしょう。しかし、見習いのうちは上の分類で十分です。上記2 つの種類にのエラーについて見ていきましょう。

誤りの例

始めるにあたり、数字当て (今回は当たらない) ゲームに戻りましょう。わざとエラーになるバージョンを見ていきます。Github に行って number-game-errors.html をローカルにコピーしてください。(ライブ実行はこちらを見てください。)

  1. 始めるには、コピーしたファイルをお好みのテキストエディターとブラウザーで開きます。
  2. ゲームで遊んでみてください。気づきましたか。"予想を入力" ボタンを押しても動きません!

: もしかしたら、あなたにも直したいと思っているバージョンがあるかもしれませんね。ですが、まずはこちらで用意したバージョンを直してみてください。そうすれば、ここで教えるテクニックが身につきます。それから、あなた自身のプログラムに戻って直してみてください。

それでは、開発者コンソールで文法エラーがあるか調べてみましょう。それからエラーを修正します。どうやって修正すればいいかは今から教えます。

文法エラーを修正する

以前に開発者ツールの JavaScript コンソールで、簡単なコマンドを入力してもらったことがあったと思います。(思い出せなければ、リンクを見て開き方を調べてください。) コンソールの何が便利かといえば、ブラウザーの JavaScript エンジンに読み込ませようとしている JavaScript コードに文法エラーがあれば、すべて教えてくれるのです。さあ、バグを潰していきましょう。

  1. number-game-errors.html ファイルを開いているタブを選択して、JavaScript コンソールを開いてください。以下のメッセージが表示されていますね。
  2. これは分かりやすいエラーです。ブラウザーからもいくつか情報が出ています。(上のスクリーンショットは FireFox のものですが、他のブラウザーでも同様の情報が表示されるでしょう。) 左から順に説明します。
    • 赤色の 「x」 ボタンはエラーがあることを示しています。
    • 「TypeError: guessSubmit.addeventListener is not a function」というエラーメッセージが、何が問題かを示しています。
    • 「詳細」 のリンクがエラー内容についての詳細を説明する MDN のページを指しています。
    • JavaScript のファイルの名前が出ています。このリンクをクリックすると、開発者ツールのデバッガータブで問題のあるファイルが開きます。ハイライトされているエラーの箇所が見えるでしょう。
    • エラーがある行の行番号と、最初の文字が始まる番号が出ています。上の例では 86行目の 3文字目です。
  3. テキストエディターで 86行目を見てみましょう。
    guessSubmit.addeventListener('click', checkGuess);
  4. エラーでは、"guessSubmit.addeventListener is not a function" とありますから、スペルミスをしたのでしょう。もし正しい綴りがわからなければ、MDN のサイトで使用している機能を調べてみてください。きっと見つかります。いつもはお好みのサーチエンジンで「mdn 機能の名前」と検索してみるのがよいでしょう。今回は代わりに addEventListener() のリンクを張っておきます。
  5. ページによると、関数の名前を間違えたみたいですね!JavaScript は大文字・小文字を区別しますので、ちょっとでも違うとエラーの原因になることを覚えておきましょう。それでは addeventListener を addEventListener に修正してエラーを直しましょう。

: TypeError: "x" is not a function のリファレンスページで、このエラーに関する詳細な説明が見られます。

文法エラーその 2

  1. ファイルを保存してブラウザーを更新すると、エラーが消えています。
  2. 予想を入力して、予想を入力ボタンを押してみると、...別のエラーが起きています!
  3. 今回のエラーを見ると、78行目で"TypeError: lowOrHi is null"が起きています。
    : Null は「何もない」ことや「値がない」ことを表す特別な値です。つまり lowOrHi が宣言されて初期化されているけれど、意味のある値ではない — つまり型も値もないということです。
    : このエラーは関数内部 (checkGuess() { ... } ブロックの中) で発生したため、ページを読み込んだだけでは出てきませんでした。後に続く関数に関する記事を読み進めていけば分かりますが、内側の関数のスコープは外側の関数のスコープとは異なります。今回のケースでは、86行目の checkGuess() 関数が実行されるまで実行されず、エラーも発生していませんでした。
  4. 78行目を見てください。以下のコードが書かれています。
    lowOrHi.textContent = '今の予想は大きすぎです!もっと小さな数字です。';
  5. この行は lowOrHi 変数の textContent プロパティに文字列を設定しようとしていますが、lowOrHi 変数に適切な値が設定されていないため上手く動きません。lowOrHi が使用されている箇所をコードのほかの部分から探してみましょう。最初に見つかるのは 48行目でしょう。
    var lowOrHi = document.querySelector('lowOrHi');
  6. ここでは、HTML の要素を参照する変数を作ろうとしています。この行の後ろで、値が null になっているか確認するため以下のコードを直後の 49行目に追加します。
    console.log(lowOrHi);

    : console.log() は値をコンソールに出力する、デバッグするときにとても便利な関数です。これで 48行目で lowOrHi にセットしたはずの値がコンソールに出力されるでしょう。

  7. ファイルを保存して再度ブラウザーで読み込みます。そして console.log() の結果をコンソールで見てみましょう。 わかりましたね。lowOrHi の値は null でした。これで問題が 48行目にあることがわかりました。
  8. それでは何が問題となり得るか考えてみましょう。48行目では要素への参照を CSS セレクタを使用して取得する document.querySelector() メソッドが使用されています。ファイルの少し上のほうにある、問題となる<p> 要素を見てみましょう。
    <p class="lowOrHi"></p>
  9. ここではクラスセレクタが必要です。クラスセレクタはドット (.) で始まりますが、48行目で querySelector() メソッドに渡された文字列にはドットがありません。これが問題でしょう!48行目の lowOrHi を .lowOrHi に変更してみてください。
  10. ファイルを保存して再度読み込むと、console.log() の文は求めていた <p> 要素を表示しています。何とか次のエラーを潰すことができました!console.log() の行は削除してもいいですし、後で使うために残しておいても大丈夫です。

: TypeError: "x" is (not) "y"  のリファレンスページで、このエラーに関する詳細な説明が見られます。

文法エラーその 3

  1. さて、もう一度ゲームをプレイしてみましょう。ゲームは問題なく動いているようです。正解するか、残りの予想回数がなくなって、ゲームが終わるまでは...。
  2. ここで、またゲームが止まってしまいました。最初のエラーと同じく "TypeError: resetButton.addeventListener is not a function" というエラーです!しかし、今回は 94行目から発生していると表示されています。
  3. 94行目を見ると、同じ間違いを犯したことがわかります。もう一度 addeventListener を .addEventListener に直してください。

論理のエラー

今回はゲームは上手く動いているようです。しかし、何度か動かしていると、予想すべき「ランダムな」数字が常に 0 か 1 であることに気づくでしょう。これはあまりやりたくないゲームですね!

これはゲームのロジックに間違いなく問題があります。ゲームはエラーとはなっていませんが、正しく動いてはいません。

  1. randomNumber 変数にランダムな数値が最初にセットされる場所を検索してみましょう。ゲームの開始で推測するランダムな数字を保存しようとしているのは 44行目のあたりです。
    var randomNumber = Math.floor(Math.random()) + 1;
    そして、それぞれのゲームの合間に次のランダムな数字を設定しているのは 113行目のあたりです。
    randomNumber = Math.floor(Math.random()) + 1;
  2. これらの行が問題となるかを確認するため、console.log() にもう一度登場してもらいましょう。先ほどのそれぞれの行の直下に以下のコードを追加します。
    console.log(randomNumber);
  3. 保存して再度読み込んで、何度かプレイしてみましょう。コンソールに出力される randomNumber の値が常に 1 であることに気づきます。

ロジックを何とかする

これを直すには、この行が何をしているのか考えなければなりません。まず Math.random() を呼んでいます。これは 0 から 1 までのランダムな実数値を生成します。例えば 0.5675493843 などです。

Math.random()

次に Math.random() の実行結果を Math.floor() に渡して、一番近い整数に切り捨てています。そしてその結果に 1 を加えます。

Math.floor(Math.random()) + 1

0 から 1 のランダムな実数を切り捨てると、結果は常に 0 となり、それに 1 を加えることで常に 1 となります。ランダムな数を切り捨てる前に 100 を乗算しなければなりません。次のコードは 0 から 99 を返すでしょう。

Math.floor(Math.random()*100);

さらに 1 を加えることで、1 から 100 のランダムな数字を返してくれるようになります。

Math.floor(Math.random()*100) + 1;

先ほどの 2行をそれぞれ修正してください。保存して再度読み込むと、思い通りに動くようになっているでしょう!

その他のよくあるエラー

コードを書いていると、よくあるエラーは他にもあります。このセクションではそれらを紹介してみましょう。

SyntaxError: missing ; before statement

たいてい、このエラーは行の末尾にセミコロン (;) がないことを意味しています。しかし、時にはかなり難解です。例えば checkGuess() 関数内の、この行を

var userGuess = Number(guessField.value);

以下のように変更してみます。

var userGuess === Number(guessField.value);

そうすると、このエラーが吐かれます。違うことをやろうとしているように見えるのでしょう。値を変数にセットする代入演算子 (=) と、ある値が別の値と同じかどうかを判定して true または false を返す等値演算子 (===) を間違わないようにしてください。

: SyntaxError: missing ; before statement  のリファレンスページで、このエラーに関する詳細な説明が見られます。

プログラムが入力の内容に関わらずいつでも勝ちだと言ってくる

これは代入と比較を混同する別の症状でしょう。たとえば、checkGuess() 関数内の、この行を

if (userGuess === randomNumber) {

以下のように変更してみます。

if (userGuess = randomNumber) {

判定で常に true が返るようになり、常にプレイヤーが勝ったことになってしまいます。気を付けましょう!

SyntaxError: missing ) after argument list

これは単純です。大体は関数やメソッドの呼び出しで閉じ括弧を忘れたことを表しています。

: SyntaxError: missing ) after argument list のリファレンスページで、このエラーに関する詳細な説明が見られます。

SyntaxError: missing : after property id

たいてい、このエラーは JavaScript のオブジェクトの書き方が正しくないことに関連しているのですが、

function checkGuess() {

上記のコードを以下のように変えても起きるでしょう。

function checkGuess( {

この変更でブラウザーは関数の内容を関数の引数として渡しているように勘違いしてしまいます。括弧には気を付けましょう!

SyntaxError: missing } after function body

これは簡単ですね。たいていの場合、関数や条件ブロックの終わりの閉じ波括弧が抜けていることを表します。checkGuess() 関数の最後の閉じ波括弧を消すと発生します。

SyntaxError: expected expression, got 'string' または SyntaxError: unterminated string literal

これらのエラーは文字列の始まりもしくは終わりのクォーテーションマークが抜けていることを表します。最初のエラーは、文字列の始めのクォーテーションマークの代わりに、ブラウザーが予期しない文字列を見つけた (string には実際に見つけた文字列が入ります) ことを表し、2 つ目のエラーは文字列がクォーテーションマークで終わっていないことを表します。

どのエラーにも言えることですが、上の例でも見たように、考えてください。エラーが起きた時に、エラーが起きた行の番号をみて、その行にエラーがあるか見てみます。エラーはその行に存在しないこともありますし、上述した理由以外で起きることもあるということを心に留めておいてください。

: SyntaxError: Unexpected token と SyntaxError: unterminated string literal のリファレンスページで、これらエラーに関する詳細な説明が見られます。

要約

やっとここまで来ましたね。簡単な JavaScript プログラムのエラーを見つけ出すための基本が理解できました。コードの間違いを解決するのがいつも簡単とは限りませんが、学習の過程でうまくいかない時があったとしても、基本を押さえていれば、多少は寝る時間が取れたり、多少の進捗もより早くあげられたりするでしょう。

関連情報

  • ここで挙げたもの以外にもいくつかのエラーの種類があります。詳細はリファレンスをご覧ください。( JavaScript エラーリファレンス )
  • この記事を読んでもまだ直し方がわからないエラーに遭遇した場合は助けを求めましょう!Learning Area Discourse スレッドや Mozilla IRC の IRC チャンネル #mdn などに聞いてください。【訳注: いずれも英語ベースのもの】。日本語では Mozilla Japan コミュニティの Slack など。どんなエラーなのか教えてくれれば、助けてあげられるかもしれません。コードを見せてくれてもいいですね。

 

このモジュール内

 

ドキュメントのタグと貢献者

このページの貢献者: Uemmra3, chameleonhead
最終更新者: Uemmra3,