JavaScript乘法游戏逻辑错误:选中正确选项但分数未递增
乘法答题游戏分数不递增问题分析
问题概述
开发了一款JavaScript乘法答题游戏:系统生成乘法题目,玩家从4个选项中选择正确答案。但发现选中正确选项时,分数并未递增,结合代码分析如下:
HTML代码
<nav> <div class="reset utilites">Reset</div> <div class="score utilites"> Score: <span class="ScoreNumber"> 0</span> </div> <div class="highScore utilites"> High Score: <span class="highScoreNumber"> 0</span> </div> </nav> <section> <div class="choices" id="1"> 🚪 <div class="answer answer1">answer</div> </div> <div class="choices" id="2"> 🚪 <div class="answer answer2">answer</div> </div> <div class="choices" id="3"> 🚪 <div class="answer answer3">answer</div> </div> <div class="choices" id="4"> 🚪 <div class="answer answer4">answer</div> </div> </section> <div class="question">---</div>
JavaScript代码
"use strict"; const resetBtn = document.querySelector(".reset"); const Navscore = document.querySelector(".ScoreNumber"); const scoreToReset = document.querySelector(".score"); const question = document.querySelector(".question"); const highScoreNumber = document.querySelector(".highScoreNumber"); const choices1 = document.getElementById("1"); const choices2 = document.getElementById("2"); const choices3 = document.getElementById("3"); const choices4 = document.getElementById("4"); const answer1 = document.querySelector(".answer1"); const answer2 = document.querySelector(".answer2"); const answer3 = document.querySelector(".answer3"); const answer4 = document.querySelector(".answer4"); const choices = document.querySelector(".choices"); let score = 0; let Highscore = 0; const numberForNumberGen = function() { return Math.trunc(Math.random() * 12 + 1); }; const choicesAssinger = function(usersChoice) { console.log(`user choice ${usersChoice}`); const answerText = questionGen(); const correct = numberGen(4); console.log(`correct choice ${correct}`); if (correct === 1) { answer1.innerHTML = answerText; answer2.innerHTML = answerText + numberForNumberGen(); answer3.innerHTML = answerText - numberForNumberGen(); answer4.innerHTML = answerText + numberForNumberGen() - numberForNumberGen(); } else if (correct === 2) { answer2.innerHTML = answerText; answer1.innerHTML = answerText - numberForNumberGen(); answer4.innerHTML = answerText - numberForNumberGen(); answer3.innerHTML = answerText + numberForNumberGen() - numberForNumberGen(); } else if (correct === 3) { answer3.innerHTML = answerText; answer4.innerHTML = answerText + numberForNumberGen(); answer2.innerHTML = answerText - numberForNumberGen(); answer1.innerHTML = answerText + numberForNumberGen() - numberForNumberGen(); } else if (correct === 4) { answer4.innerHTML = answerText; answer3.innerHTML = answerText + numberForNumberGen(); answer1.innerHTML = answerText - numberForNumberGen(); answer2.innerHTML = answerText + numberForNumberGen() - numberForNumberGen(); } console.error(correct); console.error(usersChoice); console.log(correct == usersChoice); if (correct == usersChoice) { console.log("correct"); document.querySelector("body").style.background = "green"; score++; questionGen(); choicesAssinger(); Navscore.innerHTML = score; if (score > Highscore) { Highscore = score; highScoreNumber.innerHTML = Highscore; } } else { if (score !== 0) { document.querySelector("body").style.background = " #925e36"; Navscore.innerHTML = "Please click Reset"; choices1.removeEventListener("click", handler); choices2.removeEventListener("click", handler); choices3.removeEventListener("click", handler); choices4.removeEventListener("click", handler); } } }; const start = () => { choices1.addEventListener("click", handler); choices2.addEventListener("click", handler); choices3.addEventListener("click", handler); choices4.addEventListener("click", handler); }; const numberGen = function(n) { const number = Math.trunc(Math.random() * n + 1); return number; }; const questionGen = function() { const num1 = numberGen(numberForNumberGen()); const num2 = numberGen(numberForNumberGen()); const answer = num1 * num2; console.log(answer); const questionWriting = `${num1} x ${num2}`; question.innerHTML = questionWriting; return answer; }; function handler(event) { const usersChoice = event.target.id; choicesAssinger(usersChoice); } resetBtn.addEventListener("click", () => { start(); document.querySelector("body").style.background = " #925e36"; score = 0; Navscore.innerHTML = 0; questionGen(); }); questionGen(); start();
核心失效原因
1. 递归调用直接覆盖分数更新逻辑
当用户选择正确选项后,代码执行score++后立即无参数调用choicesAssinger():
- 新的
choicesAssinger执行时,usersChoice为undefined - 新生成的随机
correct与undefined比较结果为false,进入错误分支 - 错误分支中因
score !== 0,会将Navscore内容改为"Please click Reset",直接覆盖了刚递增的分数,同时移除所有点击事件导致后续操作失效
2. 事件目标ID获取不精准
handler函数通过event.target.id获取选项ID,但用户点击选项内的子元素(如带"answer"文本的div)时,子元素无ID,导致usersChoice为空字符串,无法与数字类型的correct匹配,即使选对也会被判错误。
3. 类型不匹配的隐式转换风险
usersChoice是字符串类型(DOM元素ID默认是字符串),correct是数字类型,使用==的隐式转换容易引发不可预期的判断错误,严格来说二者类型不统一,直接比较逻辑存在漏洞。
修复方案示例
修复递归调用问题
将生成新题目的逻辑从判断分支中剥离,避免递归覆盖:
// 新增单独生成题目和选项的函数 const generateNewQuestion = function() { const answerText = questionGen(); const correct = numberGen(4); if (correct === 1) { answer1.innerHTML = answerText; answer2.innerHTML = answerText + numberForNumberGen(); answer3.innerHTML = answerText - numberForNumberGen(); answer4.innerHTML = answerText + numberForNumberGen() - numberForNumberGen(); } else if (correct === 2) { answer2.innerHTML = answerText; answer1.innerHTML = answerText - numberForNumberGen(); answer4.innerHTML = answerText - numberForNumberGen(); answer3.innerHTML = answerText + numberForNumberGen() - numberForNumberGen(); } else if (correct === 3) { answer3.innerHTML = answerText; answer4.innerHTML = answerText + numberForNumberGen(); answer2.innerHTML = answerText - numberForNumberGen(); answer1.innerHTML = answerText + numberForNumberGen() - numberForNumberGen(); } else if (correct === 4) { answer4.innerHTML = answerText; answer3.innerHTML = answerText + numberForNumberGen(); answer1.innerHTML = answerText - numberForNumberGen(); answer2.innerHTML = answerText + numberForNumberGen() - numberForNumberGen(); } return correct; }; // 修改choicesAssinger中的正确分支逻辑 if (correct == usersChoice) { console.log("correct"); document.querySelector("body").style.background = "green"; score++; Navscore.innerHTML = score; if (score > Highscore) { Highscore = score; highScoreNumber.innerHTML = Highscore; } // 调用独立函数生成新题,不再递归choicesAssinger generateNewQuestion(); }
修复事件目标ID问题
确保点击子元素时也能获取到父选项的ID:
function handler(event) { // 向上查找最近的.choices元素,稳定获取选项ID const choiceElement = event.target.closest(".choices"); const usersChoice = choiceElement.id; choicesAssinger(usersChoice); }
统一类型并使用严格相等
将usersChoice转为数字,用===做严格判断:
const choicesAssinger = function(usersChoice) { // 统一类型为数字 usersChoice = Number(usersChoice); // ...其他逻辑 if (correct === usersChoice) { // ...正确分支逻辑 } };
内容的提问来源于stack exchange,提问作者T122wd
相关产品推荐
相关产品推荐

