关于匿名函数(addEventListener)中函数与全局变量的计分器开发咨询
计分器应用:匿名事件监听器中函数与全局变量的正确用法
嘿,我来帮你搞定这个计分器应用的问题!针对你的需求,咱们可以通过合理规划全局变量和封装函数,在addEventListener的匿名回调里顺畅调用,既实现功能又让代码清晰易维护。下面是完整的实现方案,我会一步步拆解关键点:
完整代码示例
<!DOCTYPE html> <html> <head> <style> .player-score { font-size: 2rem; margin: 1rem 0; } .winner { color: green; } .game-over { pointer-events: none; opacity: 0.6; } </style> </head> <body> <p>Playing to : <span id="winning-score">5</span></p> <input type="number" id="score-input" placeholder="修改获胜分数" min="1"> <div> <h2>Player 1</h2> <p id="p1-score" class="player-score">0</p> <button id="p1-btn">Player 1</button> </div> <div> <h2>Player 2</h2> <p id="p2-score" class="player-score">0</p> <button id="p2-btn">Player 2</button> </div> <button id="reset-btn">Reset</button> <script> // 全局变量:存储游戏核心状态,供所有事件监听器共享 let p1Score = 0; let p2Score = 0; let winningScore = 5; let isGameOver = false; // DOM元素缓存(全局变量,避免重复查询DOM) const p1ScoreEl = document.getElementById('p1-score'); const p2ScoreEl = document.getElementById('p2-score'); const winningScoreEl = document.getElementById('winning-score'); const scoreInput = document.getElementById('score-input'); const p1Btn = document.getElementById('p1-btn'); const p2Btn = document.getElementById('p2-btn'); const resetBtn = document.getElementById('reset-btn'); // 封装函数:更新获胜分数 function updateWinningScore(newScore) { winningScore = parseInt(newScore); winningScoreEl.textContent = winningScore; // 如果新分数小于当前已有分数,直接重置游戏 if (p1Score >= winningScore || p2Score >= winningScore) { resetGame(); } } // 封装函数:给指定玩家加分并检查是否获胜 function addScore(playerEl, currentScore) { if (!isGameOver) { currentScore++; playerEl.textContent = currentScore; checkWin(currentScore, playerEl); return currentScore; // 返回更新后的分数,同步全局变量 } return currentScore; } // 封装函数:检查是否达到获胜分数 function checkWin(score, playerEl) { if (score === winningScore) { isGameOver = true; playerEl.classList.add('winner'); // 给按钮添加禁用样式 p1Btn.classList.add('game-over'); p2Btn.classList.add('game-over'); } } // 封装函数:重置游戏状态 function resetGame() { p1Score = 0; p2Score = 0; isGameOver = false; p1ScoreEl.textContent = '0'; p2ScoreEl.textContent = '0'; p1ScoreEl.classList.remove('winner'); p2ScoreEl.classList.remove('winner'); p1Btn.classList.remove('game-over'); p2Btn.classList.remove('game-over'); } // 匿名事件监听器中调用封装好的函数 p1Btn.addEventListener('click', function() { p1Score = addScore(p1ScoreEl, p1Score); }); p2Btn.addEventListener('click', function() { p2Score = addScore(p2ScoreEl, p2Score); }); scoreInput.addEventListener('change', function() { if (this.value >= 1) { // 确保输入合法 updateWinningScore(this.value); this.value = ''; // 清空输入框 } }); resetBtn.addEventListener('click', function() { resetGame(); }); </script> </body> </html>
关键知识点拆解
1. 全局变量的正确用法
咱们这里的全局变量都是游戏核心状态,需要在多个事件回调中共享:
p1Score/p2Score:存储当前玩家分数,每次加分后同步更新winningScore:存储获胜目标分数,支持修改isGameOver:标记游戏是否结束,防止游戏结束后继续加分- DOM元素变量:提前缓存DOM节点,避免每次事件触发都重新查询,提升性能
注意:全局变量不要滥用,只放需要跨函数共享的状态,其他局部逻辑尽量用局部变量。
2. 在匿名addEventListener中调用函数
把重复逻辑(加分、检查获胜、重置)封装成独立函数,在匿名回调里直接调用,好处是:
- 代码更简洁,避免重复写相同逻辑
- 逻辑集中,后续修改需求时只改一处函数即可
- 比如Player 1的点击回调里,只需要调用
addScore函数并同步全局分数,不用把所有逻辑堆在匿名函数里
3. 函数与全局变量的交互
比如addScore函数接收当前分数和DOM元素,处理加分后返回新分数,咱们在匿名回调里把这个返回值赋值给全局变量p1Score/p2Score,这样就能同步全局状态。这种方式比直接在函数里修改全局变量更清晰,也方便后续扩展(比如改成闭包封装状态)。
额外提示
如果不想用太多全局变量,也可以用闭包把状态封装起来,避免污染全局作用域,但对于这个小型应用来说,合理的全局变量已经足够简洁啦。
内容的提问来源于stack exchange,提问作者Pakata Goh
相关产品推荐
相关产品推荐

