控制台石头剪刀布转GUI时,getPlayerSelection函数返回undefined问题
问题:GUI版石头剪刀布无法正确获取用户选择,函数返回undefined
我正在把控制台版石头剪刀布改成GUI版本,用按钮作为用户输入渠道,但写的getPlayerSelection函数始终返回undefined。这个函数本来要获取点击按钮的文本内容作为用户选择,虽然console.log(input)能打出正确的字符串,但函数的返回值就是不对。我试过给每个按钮单独设置类名和事件监听,问题还是没解决。
HTML代码
<head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Rock Paper Scissors!</title> </head> <body> <section id="choices"> <button class="button">Rock!</button> <button class="button">Paper!</button> <button class="button">Scissors!</button> </section> <script src="javascript.js" defer></script> </body>
JavaScript代码
// player input function getPlayerSelection(){ const buttons = document.getElementsByClassName('button'); let input = ''; for (const btn of buttons) { btn.addEventListener('click', () => { input = btn.textContent; console.log(input); }) } return input; } // computer input function getComputerChoice(){ let randomChoice = Math.floor(Math.random() * 3); if(randomChoice === 0){ return("Rock!") } else if(randomChoice === 1){ return("Paper!") } else { return("Scissors!") } } function playRound(playerSelection, computerSelection) { playerSelection = getPlayerSelection(); computerSelection = getComputerChoice(); // ... 后续逻辑 }
尝试的其他代码
const rockBtn = document.querySelector('.rockButton'); rockBtn.addEventListener('click', () => { return 'Rock!'; }); const paperBtn = document.querySelector('.paperButton'); paperBtn.addEventListener('click', () => { return 'Paper!'; }); const scissorsBtn = document.querySelector('.scissorsButton'); scissorsBtn.addEventListener('click', () => { return 'Scissors!'; });
问题原因与解决方法
核心原因
- 事件监听是异步触发的:
getPlayerSelection执行时只是给按钮绑定了点击事件,随后立刻返回了初始值'',此时用户还没点击按钮,自然拿不到有效选择。用户点击按钮的动作是在函数执行完之后才会触发,这时候修改input变量已经无法改变函数的返回值了。 - 第二种尝试的写法里,事件回调的返回值不会被外部捕获,根本无法传递给
playRound函数,所以完全起不到作用。
解决方法
方法1:用Promise封装用户选择(保留原有函数结构)
把getPlayerSelection改成返回Promise,当用户点击按钮时resolve对应的值:
function getPlayerSelection(){ return new Promise((resolve) => { const buttons = document.getElementsByClassName('button'); for (const btn of buttons) { btn.addEventListener('click', () => { resolve(btn.textContent); }, { once: true }); // 确保每个按钮只触发一次,避免重复绑定 } }); } // 调用时需要用async/await处理异步 async function playRound() { const playerSelection = await getPlayerSelection(); const computerSelection = getComputerChoice(); // 这里写判断胜负的逻辑 console.log(`玩家选择:${playerSelection},电脑选择:${computerSelection}`); } // 初始化调用游戏 playRound();
方法2:直接把游戏逻辑绑定到按钮点击事件(更简单直观)
不需要单独的getPlayerSelection函数,直接在按钮点击时触发一轮游戏:
function getComputerChoice(){ let randomChoice = Math.floor(Math.random() * 3); if(randomChoice === 0){ return("Rock!") } else if(randomChoice === 1){ return("Paper!") } else { return("Scissors!") } } function playRound(playerSelection) { const computerSelection = getComputerChoice(); // 胜负判断逻辑 let result = ''; if (playerSelection === computerSelection) { result = '平局!'; } else if ( (playerSelection === 'Rock!' && computerSelection === 'Scissors!') || (playerSelection === 'Paper!' && computerSelection === 'Rock!') || (playerSelection === 'Scissors!' && computerSelection === 'Paper!') ) { result = '你赢了!'; } else { result = '你输了!'; } console.log(`${result} 玩家:${playerSelection},电脑:${computerSelection}`); } // 给所有按钮绑定点击事件 const buttons = document.getElementsByClassName('button'); for (const btn of buttons) { btn.addEventListener('click', () => { playRound(btn.textContent); }); }
内容的提问来源于stack exchange,提问作者AaronDKP
相关产品推荐
相关产品推荐

