井字棋游戏forEach循环中if/else if逻辑失效问题排查
问题描述
想要实现点击三个指定单元格时触发console.log("game over"),但当前代码中的if语句仅第一个案例生效,后续的||条件和else if分支都无法触发。尝试了两种判断逻辑:
- 匹配
cellsClicked数组与winningMoves的索引 - 判断单元格id是否为指定值(如box-1、box-2等)
两种方式均只有第一个场景能输出控制台信息,后续操作无响应。相关代码如下:
"use strict"; const gameClock = document.querySelector(".clock"); playerTitle = document.querySelector(".player-title"); const ticTacToeBoard = document.querySelector(".tic-tac-toe-container"); const cells = document.querySelectorAll(".cell"); const startPauseBtn = document.querySelector(".start-btn"); const resetBtn = document.querySelector(".resetBtn"); const cellsClicked = []; const winningMoves = [ "box-1", "box-2", "box-3", "box-4", "box-5", "box-6", "box-7", "box-8", "box-9", ]; let seconds = 0; let minutes = 0; let displaySeconds = 0; let displayMinutes = 0; let interval = null; let stopWatchStatus = "stopped"; ticTacToeBoard.classList.add("player-turn"); //functions const playerMove = () => { cells.forEach((cell) => { const playerEventListener = () => { if (ticTacToeBoard.classList.contains("player-turn")) { let currentPlayer = document.createElement("p"); currentPlayer.classList.add("player-1"); currentPlayer.innerHTML = "X"; cell.append(currentPlayer); playerTitle.innerHTML = "Player: 2"; ticTacToeBoard.classList.toggle("player-turn"); cellsClicked.push(cell.getAttribute("id")); if ( cellsClicked[0] === winningMoves[0] && cellsClicked[1] === winningMoves[1] && cellsClicked[2] === winningMoves[2] ) { console.log("game over"); } else if ( cellsClicked[3] === winningMoves[3] && cellsClicked[4] === winningMoves[4] && cellsClicked[5] === winningMoves[5] ) { console.log("game over"); } else if ( cellsClicked[6] === winningMoves[6] && cellsClicked[7] === winningMoves[7] && cellsClicked[8] === winningMoves[8] ) { console.log("game over"); } else { console.log(false); console.log(cellsClicked, winningMoves); } } else { let currentPlayer = document.createElement("p"); currentPlayer.classList.add("player-2"); currentPlayer.innerHTML = "O"; cell.append(currentPlayer); playerTitle.innerHTML = "Player: 1"; ticTacToeBoard.classList.toggle("player-turn"); if ( (cell.contains(currentPlayer) && cell.getAttribute("id") === "box-1" && cell.getAttribute("id") === "box-2" && cell.getAttribute("id") === "box-3") || (cell.contains(currentPlayer) && cell.getAttribute("id") === "box-4" && cell.getAttribute("id") === "box-5" && cell.getAttribute("id") === "box-6") || (cell.contains(currentPlayer) && cell.getAttribute("id") === "box-7" && cell.getAttribute("id") === "box-8" && cell.getAttribute("id") === "box-9") || (cell.contains(currentPlayer) && cell.getAttribute("id") === "box-1" && cell.getAttribute("id") === "box-4" && cell.getAttribute("id") === "box-7") || (cell.contains(currentPlayer) && cell.getAttribute("id") === "box-2" && cell.getAttribute("id") === "box-5" && cell.getAttribute("id") === "box-8") || (cell.contains(currentPlayer) && cell.getAttribute("id") === "box-3" && cell.getAttribute("id") === "box-6" && cell.getAttribute("id") === "box-9") || (cell.contains(currentPlayer) && cell.getAttribute("id") === "box-1" && cell.getAttribute("id") === "box-5" && cell.getAttribute("id") === "box-9") || (cell.contains(currentPlayer) && cell.getAttribute("id") === "box-3" && cell.getAttribute("id") === "box-5" && cell.getAttribute("id") === "box-7") ) { console.log("game over"); } } }; cell.addEventListener("click", playerEventListener, { once: true }); }); }; const stopWatch = () => { seconds++; if (seconds / 60 === 1) { seconds = 0; minutes++; if (minutes / 60 === 1) { minutes = 0; } } if (seconds < 10) { displaySeconds = "0" + seconds.toString(); } else { displaySeconds = seconds; } if (minutes < 10) { displayMinutes = "0" + minutes.toString(); } else { displayMinutes = minutes; } gameClock.innerHTML = `${displayMinutes}:${displaySeconds}`; }; const startStop = () => { if (stopWatchStatus === "stopped") { interval = setInterval(stopWatch, 1000); stopWatchStatus = "started"; startPauseBtn.textContent = "Pause"; } else { clearInterval(interval); stopWatchStatus = "stopped"; startPauseBtn.textContent = "Start Game"; } }; const startGame = () => { startPauseBtn.addEventListener("click", () => { if (startPauseBtn.textContent === "Start Game") { startPauseBtn.textContent = "Pause"; startStop(); } else if ((startPauseBtn.textContent = "Pause")) { startPauseBtn.textContent = "Start Game"; startStop(); } }); }; startGame(); playerMove();
问题分析
第一种判断逻辑的问题
winningMoves定义错误:应该定义为二维数组,每个子数组代表一组获胜单元格id,而非将所有id放在一维数组中。- 索引匹配逻辑错误:仅检查
cellsClicked的固定索引(如0、1、2),但玩家交替点击,获胜组合的单元格id不会恰好出现在这些固定位置,且只有当数组长度足够时,后续的else if才有可能触发,完全不符合井字棋的获胜规则。
第二种判断逻辑的问题
同一个单元格的id不可能同时等于多个值(如cell.getAttribute("id") === "box-1" && cell.getAttribute("id") === "box-2"永远为false),逻辑完全不成立,无法检测到获胜组合。
修复方案
- 重新定义所有获胜组合为二维数组
winningCombos。 - 为两个玩家分别维护已点击的单元格数组,区分不同玩家的操作。
- 抽取
checkWin函数,统一检查玩家是否达成获胜组合。 - 修复点击事件中的逻辑,每次玩家点击后调用
checkWin判断是否获胜。
修复后的代码:
"use strict"; const gameClock = document.querySelector(".clock"); let playerTitle = document.querySelector(".player-title"); const ticTacToeBoard = document.querySelector(".tic-tac-toe-container"); const cells = document.querySelectorAll(".cell"); const startPauseBtn = document.querySelector(".start-btn"); const resetBtn = document.querySelector(".resetBtn"); // 分别记录两个玩家的已点击单元格 const player1Cells = []; const player2Cells = []; // 定义所有获胜组合 const winningCombos = [ ["box-1", "box-2", "box-3"], ["box-4", "box-5", "box-6"], ["box-7", "box-8", "box-9"], ["box-1", "box-4", "box-7"], ["box-2", "box-5", "box-8"], ["box-3", "box-6", "box-9"], ["box-1", "box-5", "box-9"], ["box-3", "box-5", "box-7"] ]; let seconds = 0; let minutes = 0; let displaySeconds = 0; let displayMinutes = 0; let interval = null; let stopWatchStatus = "stopped"; ticTacToeBoard.classList.add("player-turn"); // 检查是否获胜的函数 const checkWin = (playerCells) => { return winningCombos.some(combo => { return combo.every(cellId => playerCells.includes(cellId)); }); }; const playerMove = () => { cells.forEach((cell) => { const playerEventListener = () => { const cellId = cell.getAttribute("id"); if (ticTacToeBoard.classList.contains("player-turn")) { // 玩家1操作 let currentPlayer = document.createElement("p"); currentPlayer.classList.add("player-1"); currentPlayer.innerHTML = "X"; cell.append(currentPlayer); playerTitle.innerHTML = "Player: 2"; ticTacToeBoard.classList.toggle("player-turn"); player1Cells.push(cellId); // 检查玩家1是否获胜 if (checkWin(player1Cells)) { console.log("game over - Player 1 wins!"); } } else { // 玩家2操作 let currentPlayer = document.createElement("p"); currentPlayer.classList.add("player-2"); currentPlayer.innerHTML = "O"; cell.append(currentPlayer); playerTitle.innerHTML = "Player: 1"; ticTacToeBoard.classList.toggle("player-turn"); player2Cells.push(cellId); // 检查玩家2是否获胜 if (checkWin(player2Cells)) { console.log("game over - Player 2 wins!"); } } }; cell.addEventListener("click", playerEventListener, { once: true }); }); }; const stopWatch = () => { seconds++; if (seconds >= 60) { seconds = 0; minutes++; if (minutes >= 60) { minutes = 0; } } displaySeconds = seconds < 10 ? `0${seconds}` : seconds; displayMinutes = minutes < 10 ? `0${minutes}` : minutes; gameClock.innerHTML = `${displayMinutes}:${displaySeconds}`; }; const startStop = () => { if (stopWatchStatus === "stopped") { interval = setInterval(stopWatch, 1000); stopWatchStatus = "started"; startPauseBtn.textContent = "Pause"; } else { clearInterval(interval); stopWatchStatus = "stopped"; startPauseBtn.textContent = "Start Game"; } }; const startGame = () => { startPauseBtn.addEventListener("click", () => { if (startPauseBtn.textContent === "Start Game") { startPauseBtn.textContent = "Pause"; startStop(); } else if (startPauseBtn.textContent === "Pause") { startPauseBtn.textContent = "Start Game"; startStop(); } }); }; startGame(); playerMove();
额外优化点
- 修复了
startGame函数中else if的赋值错误(原代码用了=而非===)。 - 简化了
stopWatch函数中的时间判断逻辑,更清晰可靠。 - 为
playerTitle添加了let声明,符合严格模式要求。
内容的提问来源于stack exchange,提问作者Deshawn Reid
相关产品推荐
相关产品推荐

