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

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

ただいまの
回答率

89.69%

JavascriptとHTMLでクイズを作りましたが表示されず困っています。

受付中

回答 2

投稿 編集

  • 評価
  • クリップ 1
  • VIEW 517

実現してほしい所
JavascriptをHTML上で表示させたいです。

発生した問題
Javascriptでクイズを作っています。
マニュアルに書いてある通りにクイズを作ったので、間違いがないように見えますが、

  ReferenceError: can't access lexical declaration `myQuestions' before initialization


と表示されてしまいます。何回も見直しましたが特に間違いだと思うところはありませんでした。
これが全てのコードになります。

const quizContainer = document.getElementById('quiz');
const resultsContainer = document.getElementById('results');
const submitButton = document.getElementById('submit');
function buildQuiz(){}

function showResults(){}

// display quiz right away
buildQuiz();

// on submit, show results
submitButton.addEventListener('click', showResults);
const myQuestions = [
  {
    question: "Who is the strongest?",
    answers: {
      a: "Superman",
      b: "The Terminator",
      c: "Waluigi, obviously"
    },
    correctAnswer: "c"
  },
  {
    question: "What is the best site ever created?",
    answers: {
      a: "SitePoint",
      b: "Simple Steps Code",
      c: "Trick question; they're both the best"
    },
    correctAnswer: "c"
  },
  {
    question: "Where is Waldo really?",
    answers: {
      a: "Antarctica",
      b: "Exploring the Pacific Ocean",
      c: "Sitting in a tree",
      d: "Minding his own business, so stop asking"
    },
    correctAnswer: "d"
  }
];
function buildQuiz(){
  // we'll need a place to store the HTML output
  const output = [];

  // for each question...
  myQuestions.forEach(
    (currentQuestion, questionNumber) => {

      // we'll want to store the list of answer choices
      const answers = [];

      // and for each available answer...
      for(letter in currentQuestion.answers){

        // ...add an HTML radio button
        answers.push(
          `<label>
            <input type="radio" name="question${questionNumber}" value="${letter}">
            ${letter} :
            ${currentQuestion.answers[letter]}
          </label>`
        );
      }

      // add this question and its answers to the output
      output.push(
        `<div class="question"> ${currentQuestion.question} </div>
        <div class="answers"> ${answers.join('')} </div>`
      );
    }
  );

  // finally combine our output list into one string of HTML and put it on the page
  quizContainer.innerHTML = output.join('');
}
myQuestions.forEach( (currentQuestion, questionNumber) => {
  // here goes the code we want to run for each question
});
// we'll want to store the list of answer choices
const answers = [];

// and for each available answer...
for(letter in currentQuestion.answers){

  // ...add an html radio button
  answers.push(
    `<label>
      <input type="radio" name="question${questionNumber}" value="${letter}">
      ${letter} :
      ${currentQuestion.answers[letter]}
    </label>`
  );
}

// add this question and its answers to the output
output.push(
  `<div class="question"> ${currentQuestion.question} </div>
  <div class="answers"> ${answers.join('')} </div>`
);
quizContainer.innerHTML = output.join('');
function showResults(){

  // gather answer containers from our quiz
  const answerContainers = quizContainer.querySelectorAll('.answers');

  // keep track of user's answers
  let numCorrect = 0;

  // for each question...
  myQuestions.forEach( (currentQuestion, questionNumber) => {

    // find selected answer
    const answerContainer = answerContainers[questionNumber];
    const selector = 'input[name=question'+questionNumber+']:checked';
    const userAnswer = (answerContainer.querySelector(selector) || {}).value;

    // if answer is correct
    if(userAnswer===currentQuestion.correctAnswer){
      // add to the number of correct answers
      numCorrect++;

      // color the answers green
      answerContainers[questionNumber].style.color = 'lightgreen';
    }
    // if answer is wrong or blank
    else{
      // color the answers red
      answerContainers[questionNumber].style.color = 'red';
    }
  });

  // show number of correct answers out of total
  resultsContainer.innerHTML = numCorrect + ' out of ' + myQuestions.length;
}
// gather answer containers from our quiz
const answerContainers = quizContainer.querySelectorAll('.answers');

// keep track of user's answers
let numCorrect = 0;
// for each question...
myQuestions.forEach( (currentQuestion, questionNumber) => {

  // find selected answer
  const answerContainer = answerContainers[questionNumber];
  const selector = `input[name=question${questionNumber}]:checked`;
  const userAnswer = (answerContainer.querySelector(selector) || {}).value;

  // if answer is correct
  if(userAnswer===currentQuestion.correctAnswer){
    // add to the number of correct answers
    numCorrect++;

    // color the answers green
    answerContainers[questionNumber].style.color = 'lightgreen';
  }
  // if answer is wrong or blank
  else{
    // color the answers red
    answerContainers[questionNumber].style.color = 'red';
  }
});
// find selected answer
const answerContainer = answerContainers[questionNumber];
const selector = `input[name=question${questionNumber}]:checked`;
const userAnswer = (answerContainer.querySelector(selector) || {}).value;
// if answer is correct
if(userAnswer===currentQuestion.correctAnswer){
  // add to the number of correct answers
  numCorrect++;

  // color the answers green
  answerContainers[questionNumber].style.color = 'lightgreen';
}
// if answer is wrong or blank
else{
  // color the answers red
  answerContainers[questionNumber].style.color = 'red';
}
// show number of correct answers out of total
resultsContainer.innerHTML = `${numCorrect} out of ${myQuestions.length}`;
(function(){
  // put the rest of your code here
})();


問題が発生した箇所

 // for each question...
  myQuestions.forEach(
    (currentQuestion, questionNumber) => {

      // we'll want to store the list of answer choices
      const answers = [];

自分なりの対策
何度も見直しました。

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • m.ts10806

    2018/08/07 14:16

    「見直した」は対策ではないと思います。エラーメッセージで調べて具体的にコードに反映する、デバッグをするなど実際に頭と手を動かしてください。人間の目と思い込みほど信用できないものはありません。

    キャンセル

  • hunyuchan9800

    2018/08/07 14:19

    わかりました。具体的にコードに反映してみます。

    キャンセル

回答 2

+3

基本的にプログラムでエラーが起こったときにはエラー内容に情報が詰まっています。まずはエラーの内容を把握しましょう。エラーメッセージをそのままGoogle翻訳にかけてみます。
「初期化の前に字句宣言 myQuestions にアクセスできません」
怪しい日本語ですがなんとなく意味はわかる感じがします。
エラーの出力行数からもわかりますが、エラーはfunction buildQuiz()内のmyQuestions.forEachで起こっています。
プログラムは基本的に上から下へ実行されていきます。
上から見ていくとまずconstでいくつか定義されており、その後にbuildQuiz();を実行となっており、実際のfunction buildQuiz()の中身を追っていくとmyQuestionsが...ここまでにmyQuestionsは宣言されていませんね?
function buildQuiz()内のmyQuestions.forEachより上にはmyQuestionsが書かれていますが
実際の実行順で考えるとbuildQuiz();で実行される際にはまだmyQuestionsがいないのです。
なので、エラーメッセージの通り、初期化の前にmyQuestionsにアクセスできません。つまりmyQuestionsってなんぞやと言う状態になってるわけですねー。
エラーの解決方法としてはそのままでbuildQuiz();を呼び出す前にconst myQuestionを書いてやる必要があると思われます。

また、プログラムを書く際には一気に書かずにこまめに実行し、動きを試しながら書いていくのが良いと思います。
一気に書いてしまうと最後に実行して動かなかったときにどの部分が悪くて動かないのかがわかりにくくなるためです。
まずはこの動きを作ろうとか、表示されるところを作ろうとか、部分的にやっていくと動かなくても今書いていた部分が影響しているとハッキリわかるので対処がしやすいです。

マニュアル通りに作るにしてもどの部分がどのような動きになるかの意味を追って順に書いていくと良いかと思います。(本当に全てマニュアル通りならば全部一気に書いてしまっても動きそうな感じもしますが・・・)

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

+2

そのマニュアルってのはここのことですかね。

 何が間違っているか

本文読まずにソースだけ順番にコピペしてること。

一通り記事を読んでみましたが、この記事は先に実装が空のプロトタイプ的なコードを載せ、あとから未実装部分の追加と解説を行うというスタイルでやっているようです。
なので、実装のない殻の関数→関数の中身や修正内容という順番でコードが並んでいて、そのまま順番にコピペしていくとわけのわからないコードになっていきます。
もう一度コードを見返してみてください。妙な重複がいっぱいあるでしょ。

 どうすればいいか

文章を読みながらコードを修正していく、のが最も正攻法なんですが、この本文もちょっとわかりにくいかなと感じます。(前のコードのここを直せ、みたいなところまで書いていない)
あまり初心者向けの内容ではないですね。
記事の後半に実際に動くプレイグラウンドがついています。Edit on codepenと書かれてるフレームです。(冒頭にリンクがちゃんとありますよ)
ここに最終的なスクリプトが載っていますので、それをコピーして実際に動かしてみてください。
それで、そのコードと本文を見比べながら、どんな処理をしているのか学習していってください。

 おまけ

日本語に翻訳された記事もありました。
公式
あと、関数名やコメントで検索したら同じようなコードがたくさん見つかりました。どれかがオリジナルなんでしょうね。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

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

  • ただいまの回答率 89.69%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる