Project1-猜数字
command + S,保存文件; command + k,清空终端 按cl并空格自动转成console.log(); 字符串拼接用 +=;
给定1-20的随机数字,用户猜测是什么数字,根据大小给予用户提示是太大还是太小,初始给一个20的分数,每错一次减1,当分数到0游戏失败。
1、鲁棒性检查
let secretNumber = Math.trunc(Math.random() * 20) + 1; //1-20
let score = 20;
console.log(`secretNumber is ${secretNumber}`);
//给check按钮添加事件处理,传入动作(点击)和函数两个参数(函数也是一种值,可以作为实参被传递),我们先直接在该函数参数里写函数体。
//当用户点击按钮,就会触发该点击事件,它会执行函数,函数应该先进行鲁棒性检查,再对比输入的数字与secret数字。
document.querySelector('.btn.check').addEventListener('click', function () {
//⚠️我们在html的input标签中指定了输入类型得是number,所以用户无法输入字符,但可以啥也不输入
//所以鲁棒性只需检查:用户是否输入了
//⚠️从页面传入的内容都是string类型!所以若用户什么也没输入,传入的是''
//所以我们的思路:先对传入的字符串检查是否为空字符串,再转换成Number类型比较大小
//注意为什么不要先转换再检查鲁棒性,因为''转换成Number类型会变成0,就无法和输入的数字0区分了。
//鲁棒性检查:
const userInput = document.querySelector('.guess').value; //input元素的内容用.value去获取
console.log(userInput, typeof userInput);
if (userInput === '') {
document.querySelector('.message').textContent = '🈲 No Number!';
return;
}
2、处理游戏失败
结论:游戏失败的条件是score <==1;而不是score <==0!在代码中,为了防止游戏失败后用户继续点击check导致score继续变化,我们把判断是否继续游戏的条件写成score <==1,总而言之,记住,能写成<== 或>==就写成。
额外:游戏胜利和失败游戏都应该结束,就不能再猜了,为了实现这个,增加一个变量playing = true;当游戏胜利或失败,设置为false,只有playing为true,两个主函数的逻辑才能继续
//转换成Number:
const guess = Number(userInput);
//先构建三种情况下score的变化和UI的更新,再考虑怎么处理游戏失败。
//⚠️⚠️当分数到0时游戏失败,但这里有个注意点:
//游戏失败的节点应该是:当score为1时(仅剩1次机会),用户再次check,但依然错误。
//代码运行逻辑上则是:用户点击check,事件执行函数,发现猜测的数字又不对,进入过大或过小分支
//然后检查score,发现<==1(用<==1,防止归零后用户还点击check),那么进行游戏失败的相关更新;
//否则游戏继续(指进行猜测数字过大/过小的更新)
if (guess === secretNumber) {
//猜对了,score不需更新,只有猜错了,score-1 document.querySelector('.message').textContent = '🎉 Correct Number!';
document.querySelector('.number').textContent = secretNumber;
//在css中,写作backgroud-color,但js中需写成驼峰法:
document.querySelector('body').style.backgroundColor = '#60b347'; //需写成字符串
document.querySelector('.number').style.width = '30rem'; //
}
if (guess < secretNumber) {
if (score <= 1) {
//游戏失败
//不是<=0!
document.querySelector('.message').textContent = '💥 You lost the game!';
document.querySelector('.score').textContent = 0; //直接更新成0.
} else {
//score > 1
document.querySelector('.message').textContent = '📉 Too low!!';
score--;
document.querySelector('.score').textContent = score;
return;
}
}
if (guess > secretNumber) {
if (score <= 1) {
//游戏失败
//you
document.querySelector('.message').textContent = '💥 You lost the game!';
document.querySelector('.score').textContent = 0;
} else {
document.querySelector('.message').textContent = 'Bigger!!';
score--;
document.querySelector('.score').textContent = score;
return;
}
}
});
先说直觉版(人类思维):
游戏有 20 分,每猜错一次扣 1 分。
当分数变成 0,说明你没机会了 → 游戏结束。
所以你脑子里是这么想的:
“只要分数大于 0,我就还能再猜;
当我按下按钮并扣到 0 的那一刻,我就输了。”
🧠再说程序版(计算机思维):
计算机不会主动知道“这是你最后一次机会” 。
它只会在你点击按钮那一刻执行一次事件函数。
逻辑顺序是这样的:
-
你点击“Check!”
-
程序执行函数体(一次判断流程)
-
在函数执行期间:
- 它先去检查你输入的数字;
- 再去看你当前的分数;
- 再决定是否还要继续游戏(继续游戏指的是处理过大/过小)。 换句话说,对程序而言:
游戏失败”不是当 score <== 0 时触发的,
而是当本轮操作将要让分数变成 0时触发的。
计算机要提前一步识别“下一个状态就是失败”, 而如果判断写成 score <== 0:
- 当 score === 1 时,程序会进入“继续”分支(处理过大/过小);
- 扣完分后 score 变成 0;
- 但本轮已经执行完毕,没有再去检查;
- 结果就是:你已经输了,但游戏界面还没提示失败。
3.重置游戏
//重新开始游戏
document.querySelector('.btn.again').addEventListener('click', function () {
//重置变量:随机数、分数
secretNumber = Math.trunc(Math.random() * 20) + 1; //1-20
score = 20;
console.log(`secretNumber is ${secretNumber}`);
//重置html:
document.querySelector('.message').textContent = 'Start guessing...';
document.querySelector('.score').textContent = 20;
document.querySelector('.guess').value = '';
document.querySelector('.number').textContent = '?';
//重置css:
document.querySelector('body').style.backgroundColor = '#222';
document.querySelector('.number').style.width = '15rem';
});
4.最高分
只需游戏结束的时候更新最高分:但游戏失败代表分数扣到0了,所以没必要更新最高分,因为0肯定<=最高分;所以只需要在猜对的时候,取当前最高分和当前分数更高的那个到最高分里,并更新html。 更新最高分,不仅要更新变量,也要更新html.
5.重构:不要重复自己原则
重构1-把两个几乎相同的分支合并为一个
//重构1,把两个几乎相同的分支合并为一个:过大过小两个分支只有Too high/Too low文本更新不一样
if (guess !== secretNumber) {
if (score <= 1) {
document.querySelector('.message').textContent = '💥 You lost the game!';
document.querySelector('.score').textContent = 0; //直接更新成0.
} else {
document.querySelector('.message').textContent =
guess > secretNumber ? '📈 Too High' : '📉 Too low';
score--;
document.querySelector('.score').textContent = score;
}
}
重构2-构造函数消除重复
对message 文本元素的更新出现了很多行:
还有对number文本元素的更新也是,生成随机数也是,所以我们构造函数去更新这些html文本和生成随机数。
const displayMessage = function (message) {
document.querySelector('.message').textContent = message;
};
const displayNumber = function (number) {
document.querySelector('.number').textContent = number;
};
const createSecretNumber = function () {
return Math.trunc(Math.random() * 20) + 1; //1-20
};
let secretNumber = createSecretNumber(); //Math.trunc(Math.random() * 20) + 1; //1-20
let score = 20;
let highScore = 0;
console.log(`secretNumber is ${secretNumber}`);