You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让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()传递有效的选项字符串参数。


解决方案

核心问题分析

  1. 原prompt是同步阻塞式逻辑,能直接返回结果;但点击按钮是异步事件,无法通过return直接返回值,必须用事件驱动或回调函数的方式处理用户选择。
  2. 箭头函数没有独立的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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 20:40:18