如何让getUserChoice通过forEach和EventListener返回可用于playRound的有效字符串参数?
问题描述
我正在用DOM方法给石头剪刀布游戏添加UI并重写逻辑,现有两个可用函数:
getComputerChoice():随机返回小写的"rock"/"paper"/"scissors"字符串playRound(computerChoice, userChoice):接收两个选项字符串,比较后输出结果(部分代码如下)
function playRound(computerChoice, userChoice) { if (userChoice === computerChoice) { console.log("----------------"); console.log("Draw!"); console.log("User choice was: " + userChoice); console.log("Computer choice was: " + computerChoice); console.log("----------------"); } // 其他胜负判断逻辑省略 }
原来的getUserChoice()用prompt获取输入并返回小写字符串,能正常给playRound()传参:
function getUserChoice() { let userChoice = prompt("What is your weapon? "); return userChoice.toLowerCase(); }
现在改成通过点击按钮获取选择(按钮ID对应选项),修改后的getUserChoice()无法给playRound()提供有效参数,userChoice总是undefined;另外箭头函数里的this是undefined:
function getUserChoice() { const userChoice = document.querySelectorAll('button'); userChoice.forEach((choice) => { choice.addEventListener('click', () => { console.log("this: " + this.id); // this是undefined console.log(choice.id); // 能正确打印按钮ID,但无法返回给playRound }) }) }
对应的HTML结构:
<div class="buttons"> <button id="rock">Rock</button> <button id="paper">Paper</button> <button id="scissors">Scissors</button> </div>
需求:修改getUserChoice()(必须使用.forEach和EventListener),使其能给playRound()传递有效的选项字符串参数。
解决方案
核心问题分析
- 原
prompt是同步阻塞式逻辑,能直接返回结果;但点击按钮是异步事件,无法通过return直接返回值,必须用事件驱动或回调函数的方式处理用户选择。 - 箭头函数没有独立的
this上下文,会继承外层作用域的this,所以点击事件里用箭头函数时this指向不是按钮元素;改用普通函数或通过事件对象的target属性,就能拿到正确的按钮元素。
修改后的代码实现
方法1:直接在点击事件中触发游戏回合
把游戏逻辑直接绑定到按钮点击事件上,是最直接的实现方式:
// 初始化按钮监听,点击时执行游戏回合 function initGameButtons() { const buttons = document.querySelectorAll('button'); buttons.forEach((button) => { // 用普通函数作为回调,this指向当前点击的按钮 button.addEventListener('click', function() { const userChoice = this.id; const computerChoice = getComputerChoice(); // 直接调用playRound处理当前回合 playRound(computerChoice, userChoice); }); }); } // 页面加载完成后初始化监听,避免DOM未加载完成时获取不到按钮 document.addEventListener('DOMContentLoaded', initGameButtons);
方法2:用回调函数传递用户选择
如果需要保留getUserChoice的结构,可以通过回调函数把用户选择传递出去:
function getUserChoice(callback) { const buttons = document.querySelectorAll('button'); buttons.forEach((button) => { button.addEventListener('click', (event) => { // 用event.target.id获取按钮ID,适合箭头函数场景 const userChoice = event.target.id; // 调用回调函数,把用户选择传入 callback(userChoice); }); }); } // 使用方式:传入playRound的调用逻辑作为回调 document.addEventListener('DOMContentLoaded', () => { getUserChoice((userChoice) => { const computerChoice = getComputerChoice(); playRound(computerChoice, userChoice); }); });
关键修改点说明
- 放弃从
getUserChoice()直接返回值的思路,因为异步事件无法同步返回结果,转而在事件触发时处理游戏逻辑。 - 点击事件回调如果用普通函数,
this会指向被点击的按钮,可直接通过this.id获取选择;如果用箭头函数,就用event.target.id获取按钮ID。 - 必须在
DOMContentLoaded事件中初始化监听,确保DOM元素加载完成后再绑定事件,避免出现获取不到按钮的情况。
内容的提问来源于stack exchange,提问作者FacundoGB
相关产品推荐
相关产品推荐

