JavaScript游戏二次运行变量未初始化问题及fetch变量初始化咨询
问题分析与解决方案
你的推测方向是对的,但问题不止是变量未重置——事件重复绑定才是导致第二次游戏出错的核心原因,变量作用域的问题和它交织在一起,共同引发了错误。
核心问题拆解
事件重复绑定
你在fetch的成功回调里绑定了.choice和.retry的点击事件,这意味着每次点击Start按钮,都会给.btn元素新增一套事件监听。第二次游戏时,点击选项会同时触发第一次和第二次绑定的回调,导致clicked和correct被多次累加,逻辑彻底混乱。变量作用域与重置
clicked和correct是在start点击事件内部用let声明的,每次点击Start确实会重新创建这两个变量,但旧的事件回调仍然引用第一次的变量实例。第二次游戏时,新旧回调会同时修改不同的变量副本,数据完全不对。
修复后的完整代码
var apikey = "https://opentdb.com/api.php?amount=2&type=multiple"; // 把变量提升到外层作用域,方便全局重置和访问 let clicked = 0; let correct = 0; // 存储当前题目数据,避免回调闭包问题 let currentQuiz = null; // 只绑定一次事件委托,动态元素也能生效 $(".btn").on("click", ".start", function() { // 每次开始游戏强制重置变量 clicked = 0; correct = 0; $(".header").text("Is fetching..."); $(".content").text("just a moment please"); $(".start").hide(); $(".category").show(); $(".difficulty").show(); fetch(apikey) .then(response => response.json()) .then(json => { currentQuiz = json; display(currentQuiz, clicked); }); }); $(".btn").on("click", ".choice", function() { if (!currentQuiz) return; // 防止未加载完成时点击 console.log("clicked", clicked); correct += $(this).html() === currentQuiz.results[clicked].correct_answer ? 1 : 0; clicked++; console.log(correct); if (clicked === currentQuiz.results.length) { showresult(correct); } else { display(currentQuiz, clicked); } }); $(".btn").on("click", ".retry", function() { document.querySelector('.btn').innerHTML = "<button class='start'>start</button>"; }); function display(json, clickedIdx) { const arr = [json.results[clickedIdx].correct_answer].concat(json.results[clickedIdx].incorrect_answers); // 先复制数组再打乱,避免原数组被多次修改导致选项重复 const shuffledArr = shuffle([...arr]); $(".header").text("Question" + Number(clickedIdx + 1)); $(".category").text("[category] : " + json.results[clickedIdx].category); $(".difficulty").text("[difficulty] : " + json.results[clickedIdx].difficulty); $(".content").text(json.results[clickedIdx].question); let html = ""; for (let i = 0; i < shuffledArr.length; i++) { html += "<button class='choice'>" + shuffledArr[i] + "</button><br>"; } document.querySelector('.btn').innerHTML = html; } function showresult(correctCount) { $(".header").text("Number of correct answers is " + correctCount); $(".category").hide(); $(".difficulty").hide(); $(".content").text("Challenge again"); document.querySelector('.btn').innerHTML = "<button class='retry'>retry</button>"; } function shuffle(array) { var currentIndex = array.length, temporaryValue, randomIndex; while (0 !== currentIndex) { randomIndex = Math.floor(Math.random() * currentIndex); currentIndex -= 1; temporaryValue = array[currentIndex]; array[currentIndex] = array[randomIndex]; array[randomIndex] = temporaryValue; } return array; }
关键修改点说明
- 事件委托优化:把
.choice和.retry的事件监听移到外部,只绑定一次,避免重复绑定导致的多次触发问题。 - 变量重置逻辑:将
clicked和correct提升到外层,每次点击Start时强制重置为0,确保第二次游戏初始状态正确。 - 题目数据存储:新增
currentQuiz变量存储当前题目数据,解决原代码中闭包导致的无法访问最新数据的问题。 - 洗牌逻辑修正:复制数组后再打乱,避免原数组被多次修改导致选项重复显示。
- UI状态恢复:在Start点击时恢复
category和difficulty的显示,避免第二次游戏时这些元素隐藏。
内容的提问来源于stack exchange,提问作者Heisenberg
相关产品推荐
相关产品推荐

