现在您在学习一些关于JavaScript的理论,以及您可以拿它来做些什么。通过一个完整的练习指导,我们将会带给您一个了解JavaScript基本功能的速成课。在这里您一步接一步地将会建立一个简单的“猜数字”游戏。
前提: | 基本的计算机知识,对HTML和CSS初步了解,知道JavaScript是什么。 |
---|---|
目标: | 拥有一点编写JavaScript的经验,至少会获得关于编写JavaScript时应当涉及到些什么的基本认识。 |
您不会被要求立即理解所有代码的细节——现在我们只是想把高级概念介绍给您,以及给您一个JavaScript(以及其他编程语言)是如何工作的。在随后的文章中,你将会再次看到这些功能的更多细节。
Note: 你在JavaScript中看到的许多代码特性和其他编程语言类似— 函数、循环,等等。 代码语法看起来不同,但是在概念上是基本类似的。
像程序员一样思考
在编程中学习的最困难的事情之一不是我们需要学习的语法,而是如何应用它来解决现实世界的问题。 您需要像一个程序员一样开始思考——这通常涉及到对程序需要做什么样描述,以及实现这些东西需要什么代码特性,以及如何使它们一起工作。
这需要努力工作,编程语法的经验和实践的混合,以及一点创造力。 我们编写的代码越多,我们的本领就越好。 我们不能保证您将在5分钟内开发“程序员大脑”,但我们将给您很多机会像整个课程中的程序员一样练习思维。
考虑到这一点,让我们看看我们将在本文中构建的示例,并查看将其分解为有形任务的一般过程。
例子— 猜数字游戏
在本文中,我们将向您演示如何构建您在下面看到的简单游戏:
Top hidden code
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Number guessing game</title> <style> html { font-family: sans-serif; } body { width: 50%; max-width: 800px; min-width: 480px; margin: 0 auto; } .lastResult { color: white; padding: 3px; } </style> </head> <body> <h1>Number guessing game</h1> <p>We have selected a random number between 1 and 100. See if you can guess it in 10 turns or less. We'll tell you if your guess was too high or too low.</p> <div class="form"> <label for="guessField">Enter a guess: </label><input type="text" id="guessField" class="guessField"> <input type="submit" value="Submit guess" class="guessSubmit"> </div> <div class="resultParas"> <p class="guesses"></p> <p class="lastResult"></p> <p class="lowOrHi"></p> </div> </body> <script> // Your JavaScript goes here var randomNumber = Math.floor(Math.random() * 100) + 1; var guesses = document.querySelector('.guesses'); var lastResult = document.querySelector('.lastResult'); var lowOrHi = document.querySelector('.lowOrHi'); var guessSubmit = document.querySelector('.guessSubmit'); var guessField = document.querySelector('.guessField'); var guessCount = 1; var resetButton; function checkGuess() { var userGuess = Number(guessField.value); if (guessCount === 1) { guesses.textContent = 'Previous guesses: '; } guesses.textContent += userGuess + ' '; if (userGuess === randomNumber) { lastResult.textContent = 'Congratulations! You got it right!'; lastResult.style.backgroundColor = 'green'; lowOrHi.textContent = ''; setGameOver(); } else if (guessCount === 10) { lastResult.textContent = '!!!GAME OVER!!!'; lowOrHi.textContent = ''; setGameOver(); } else { lastResult.textContent = 'Wrong!'; lastResult.style.backgroundColor = 'red'; if(userGuess < randomNumber) { lowOrHi.textContent='Last guess was too low!' ; } else if(userGuess > randomNumber) { lowOrHi.textContent = 'Last guess was too high!'; } } guessCount++; guessField.value = ''; } guessSubmit.addEventListener('click', checkGuess); function setGameOver() { guessField.disabled = true; guessSubmit.disabled = true; resetButton = document.createElement('button'); resetButton.textContent = 'Start new game'; document.body.appendChild(resetButton); resetButton.addEventListener('click', resetGame); } function resetGame() { guessCount = 1; var resetParas = document.querySelectorAll('.resultParas p'); for(var i = 0 ; i < resetParas.length ; i++) { resetParas[i].textContent=''; } resetButton.parentNode.removeChild(resetButton); guessField.disabled = false; guessSubmit.disabled = false; guessField.value=''; guessField.focus(); lastResult.style.backgroundColor='white'; randomNumber=Math.floor(Math.random() * 100) + 1; } </script> </html>
这里有个游戏,在继续阅读之前,您可以试玩几盘熟悉下规则。
不妨设想,老板给了以下要求并让您设计一个游戏
我想让你创建一个可以猜数字的游戏,它会在1~100以内随机选择一个数, 然后让玩家挑战在10轮以内猜出这个数字,每一轮都要告诉玩家正确或者错误, 如果出错了,则告诉他数字是低了还是高了,并且还要告诉玩家之前猜的数字是什么。 一旦玩家猜测正确,或者他们用完了回合,游戏将结束。 游戏结束后,可以让玩家选择再次开始。
看到这个要求,我们可以做的第一件事是开始把它分解成简单的可操作的任务,尽可能从程序员的思维去思考:
- 生成1到100之间的随机数。
- 记录玩家在第几轮。从1开始。
- 为玩家提供一种猜测数字的方法。
- 一旦提交了猜测,首先将它记录在某处,以便用户可以看到他们先前的猜测。
- 接下来检查它是否是正确的数字。
- 如果是正确的:
- 显示祝贺消息。
- 阻止玩家输入更多的猜测(这会使游戏混乱)。
- 显示控制允许玩家重新开始游戏。
- 如果它错了,并且玩家有剩余轮次:
- 告诉玩家他们错了。
- 允许他们输入另一个猜测。
- 将圈数增加1。
- 如果它是错误的,并且玩家没有剩余轮次:
- 告诉玩家游戏结束。
- 阻止玩家输入更多的猜测(这会使游戏混乱)。
- 显示控制允许玩家重新开始游戏。
- 一旦游戏重新启动,请确保游戏逻辑和用户界面完全重置,然后返回步骤1。
让我们继续前进,看看我们如何将这些步骤转换为代码,构建示例,并探索JavaScript功能。
初始设置
开始本教程前,我们希望您能拷贝一份本地副本 number-guessing-game-start.html (see it live here)。在文本编辑器和Web浏览器中打开它,此时,您将看到一个简单的标题,用于输入猜测的说明和形式段,但表单目前不会执行任何操作。
我们将添加的所有代码放在HTML底部的 <script> 元素中:
<script> // Your JavaScript goes here </script>
添加变量以保存数据
让我们开始吧。 首先,在(“script”)元素中添加以下行:
var randomNumber = Math.floor(Math.random() * 100) + 1; var guesses = document.querySelector('.guesses'); var lastResult = document.querySelector('.lastResult'); var lowOrHi = document.querySelector('.lowOrHi'); var guessSubmit = document.querySelector('.guessSubmit'); var guessField = document.querySelector('.guessField'); var guessCount = 1; var resetButton;
这部分代码设置了我们需要存储我们的程序将使用的数据的变量。 变量基本上是值的容器(例如数字或文本字符串)。 您可以使用关键字var以及变量的名称创建一个变量。 然后,您可以使用等号(=)和您要赋予的值为变量赋值。
在我们的示例中:
- 第一个变量 - randomNumber - 被分配一个1到100之间的随机数,使用数学算法计算。
- 接下来的三个变量都用于存储对HTML中的结果段落的引用,并用于在代码的后面段落中插入值:
-
<p class="guesses"></p> <p class="lastResult"></p> <p class="lowOrHi"></p>
- 接下来的两个变量存储对表单文本输入和提交按钮的引用,并用于控制以后提交猜测:
<label for="guessField">Enter a guess: </label><input type="text" id="guessField" class="guessField"> <input type="submit" value="Submit guess" class="guessSubmit">
- 我们的最后两个变量存储一个猜测计数1(用于跟踪玩家有多少猜测),以及一个不存在的引用(但稍后会有)。
Note: 稍后在课程中,您将学到更多关于变量的信息 , starting with the next article.
函数(Function)
接下来,在您之前写入的JavaScript代码段中添加以下内容:
function checkGuess() { alert('I am a placeholder'); }
该代码通过键入函数的名称后跟括号运行。
请尝试立即保存您的代码,然后在浏览器中刷新。
进入 developer tools JavaScript console, 并输入以下代码:
checkGuess();
您应该看到了一个警报,“I am a placeholder”; 我们在代码中定义了一个函数,当我们调用它时,函数创建了一个警报。
Note: 在课程后面你会学到更多关于函数的知识。
运算符(Operators)
JavaScript运算符允许我们执行比较,做数学运算,连接字符串,以及其他类似的事情。
让我们保存代码并刷新浏览器中显示的页面。 如果您还没有打开 developer tools JavaScript console ,或者说您无法访问浏览器开发人员工具,您可以使用使用下面所示的简单内置控制台——您可以尝试键入下面所示的示例代码,并在每个命令输入完毕之后按下Return / Enter,查看他们执行后的返回结果。
Hidden code
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>JavaScript console</title> <style> * { box-sizing: border-box; } html { background-color: #0C323D; color: #809089; font-family: monospace; } body { max-width: 700px; } p { margin: 0; width: 1%; padding: 0 1%; font-size: 16px; line-height: 1.5; float: left; } .input p { margin-right: 1%; } .output p { width: 100%; } .input input { width: 96%; float: left; border: none; font-size: 16px; line-height: 1.5; font-family: monospace; padding: 0; background: #0C323D; color: #809089; } div { clear: both; } </style> </head> <body> </body> <script> var geval = eval; function createInput() { var inputDiv = document.createElement('div'); var inputPara = document.createElement('p'); var inputForm = document.createElement('input'); inputDiv.setAttribute('class','input'); inputPara.textContent = '>'; inputDiv.appendChild(inputPara); inputDiv.appendChild(inputForm); document.body.appendChild(inputDiv); inputDiv.focus(); inputForm.addEventListener('change', executeCode); } function executeCode(e) { try { var result = geval(e.target.value); } catch(e) { var result = 'error — ' + e.message; } var outputDiv = document.createElement('div'); var outputPara = document.createElement('p'); outputDiv.setAttribute('class','output'); outputPara.textContent = 'Result: ' + result; outputDiv.appendChild(outputPara); document.body.appendChild(outputDiv); e.target.disabled = true; e.target.parentNode.style.opacity = '0.5'; createInput() } createInput(); </script> </html>
首先让我们来看看算术运算符,例如:
Operator | Name | Example |
---|---|---|
+ |
Addition | 6 + 9 |
- |
Subtraction | 20 - 15 |
* |
Multiplication | 3 * 7 |
/ |
Division | 10 / 5 |
您也可以使用+运算符将文本字符串连接在一起(在编程中称为连接)。 尝试输入以下行:
var name = 'Bingo'; name; var hello = ' says hello!'; hello; var greeting = name + hello; greeting;
还有一些快捷操作符可用,称为增强赋值操作符。 例如,如果您想简单地添加一个新的文本字符串到一个现有的并返回结果,您可以这样做:
name += ' says hello!';
这相当于
name = name + ' says hello!';
当我们执行true / false比较时(例如在条件语句 - 见下面),我们使用比较运算符,例如:
Operator | Name | Example |
---|---|---|
=== |
Strict equality (is it exactly the same?) | 5 === 2 + 4 |
!== |
Non-equality (is it not the same?) | 'Chris' !== 'Ch' + 'ris' |
< |
Less than | 10 < 6 |
> |
Greater than | 10 > 20 |
条件(Conditionals)
回到我们的checkGuess()函数,现如今,我们不希望它只是吐出一个占位符消息。 我们希望它能够检查玩家的猜测是否正确,并做出适当的反应。
现在,将您当前的checkGuess()函数替换为此版本:
function checkGuess() { var userGuess = Number(guessField.value); if (guessCount === 1) { guesses.textContent = 'Previous guesses: '; } guesses.textContent += userGuess + ' '; if (userGuess === randomNumber) { lastResult.textContent = 'Congratulations! You got it right!'; lastResult.style.backgroundColor = 'green'; lowOrHi.textContent = ''; setGameOver(); } else if (guessCount === 10) { lastResult.textContent = '!!!GAME OVER!!!'; setGameOver(); } else { lastResult.textContent = 'Wrong!'; lastResult.style.backgroundColor = 'red'; if(userGuess < randomNumber) { lowOrHi.textContent = 'Last guess was too low!'; } else if(userGuess > randomNumber) { lowOrHi.textContent = 'Last guess was too high!'; } } guessCount++; guessField.value = ''; guessField.focus(); }
这有很多代码,让我们给您逐段解释它的意图。
- 第一行(上面的第2行)声明了一个名为userGuess的变量,并将其值设置为在文本字段中输入的当前值。 我们还通过内置的Number()方法运行这个值,只是为了确保该值绝对是一个数字。
- 接下来,我们遇到我们的第一个条件代码块(上面的第3-5行)。 条件代码块允许您根据某个条件是否为真从而选择性地运行代码。 它看起来有点像一个函数,但它不是。 条件块的最简单形式是从关键字if开始,然后是一些括号,然后是一些花括号。 在括号内,我们包含了一个比较。 如果比较返回true,就会执行放在花括号中的代码。 反之,花括号中的代码就会被跳过,从而执行下一行代码。 在这种情况下,比较是测试guessCount变量是否等于1,即玩家是不是第一次猜数字:
-
guessCount === 1
如果是, 我们让 guesses 段落的文本内容等于"Previous guesses: "。如果不是,那就说明我们已经执行过了文本设定,那就无需再次设定了。 - 第6行将当前userGuess值附加到guesses段落的末尾,并加上一个空格,因此在每个猜测值之间将有一个空格。
- 下一个代码块中(上面的第8-24行)做了几个检查:
- 第一个if(){ } 检查用户的猜测是否等于在代码顶端设置的randomNumber值。如果是,则玩家猜对了,游戏胜利,我们将向玩家显示一个漂亮的绿色的祝贺信息,并清除猜测信息框的内容,调用setgameover()方法。
紧接着我们又写了一个else if(){ }
结构。它会检查这个回合是否是玩家的最后一个回合。如果是,程序将做与前一个程序块相同的事情,除了它显示的是game over而不是祝贺消息。- 最后的一个块是
else { },
其中包含着前面两个比较都为false才会执行的代码,即玩家还有游戏的次数但是本次没猜对。在这个情况下,我们会告诉玩家他们猜错了,并执行一个条件测试,判断并告诉玩家猜测的数字是大是小。
- 这个函数最后三行 (上面的第26–28行) 让我们为下次猜测值提交做好准备。我们把
guessCount
变量的值+1,因此玩家消耗了一次机会 (++
是一个递增操作符 — 将值+1),然后我们把文本段的值清空,重新将焦点设置在文本段里,准备下一轮游戏。
事件(Events)
现在,我们有一个实现比较不错的checkGuess()函数了,但它现在不会做任何事情,因为我们还没有调用它。 理想情况是,我们希望在按下“Submit guess”按钮时调用它,为此,我们需要使用事件。 事件是浏览器中发生的动作,例如点击按钮,加载页面或播放视频,我们可以调用代码来响应。 侦听事件发生的构造方法称为事件监听器,响应事件触发而运行的代码块被称为事件处理器。
在checkGuess()函数的结束大括号后添加以下代码:
guessSubmit.addEventListener('click', checkGuess);
这里我们为guessSubmit按钮添加了一个监听事件。这个方法包含两个可输入值(参数),监听事件的类型(在本例中为“点击”),和当事件发生时我们想要执行的代码(在本例中为checkGuess()函数)——注意,当函数作为事件监听方法的参数时,函数名后不应带括号。
保存您的代码并刷新页面,示例某些功能现在应该能正常工作了。 现在唯一的问题是,如果你猜到正确的答案或游戏次数已使用完,游戏将发生错乱,因为我们还没有定义应该在游戏结束后运行的setGameOver()函数。 现在,让我们添加缺少的代码,并完成示例功能。
完善游戏
让我们将setGameOver()函数添加到代码底部,然后再来看看它:
function setGameOver() { guessField.disabled = true; guessSubmit.disabled = true; resetButton = document.createElement('button'); resetButton.textContent = 'Start new game'; document.body.appendChild(resetButton); resetButton.addEventListener('click', resetGame); }
- 前两行禁用表单文本输入和按钮,方法是将其disable属性设置为true。 这是有必要的,如果我们没有禁用,用户可以在游戏结束后提交更多的猜测,这会破坏游戏的规则。
- 接下来的三行创建了一个新的button元素,设置它的文本为“Start new game”,并把它添加到我们文档的底部。
- 最后一行在我们的新按钮上设置了一个事件监听器,当它被点击时,一个名为resetGame()的函数被将被调用。
现在我们需要定义resetGame()这个函数了! 将以下代码添加到代码底部:
function resetGame() { guessCount = 1; var resetParas = document.querySelectorAll('.resultParas p'); for (var i = 0 ; i < resetParas.length ; i++) { resetParas[i].textContent = ''; } resetButton.parentNode.removeChild(resetButton); guessField.disabled = false; guessSubmit.disabled = false; guessField.value = ''; guessField.focus(); lastResult.style.backgroundColor = 'white'; randomNumber = Math.floor(Math.random() * 100) + 1; }
这个相当长的代码块完全重置了一切:
- 将guessCount重置为1。
- 清除所有信息段落。
- 从我们的代码中删除重置按钮。
- 启用表单元素,并清空和聚焦文本字段,准备接受用户输入的新猜测。
- 从lastResult段中删除背景颜色。
- 生成一个新的随机数,这样下次您就是在猜测新的数字了!
现在,您应该有一个能完整工作的(简单)游戏了——恭喜您 。
我们现在来讨论下其他很重要的代码功能,你可能已经看到过,但是你可能没有意识到这一点。
循环(Loops)
上面代码的一部分,我们需要更详细地看一下 for 循环。 循环在编程中是一个非常重要的概念,它允许你一直重复运行一段代码,直到满足某个条件。
首先,请再次转到 浏览器开发工具 JavaScript 控制台然后输入以下内容:
for (var i = 1 ; i < 21 ; i++) { console.log(i) }
发生了什么? 数字1到20在控制台中打印出来。 这是因为循环。 for循环需要三个输入值(参数):
- 起始值:在这种情况下,我们开始计数为1,但这可以是任何你喜欢的数字。 你可以用任何你喜欢的名字替换我,但我用作一个约定,因为它很短,很容易记住。
- 退出条件:这里我们指定i小于21 - 循环将继续,直到i不再小于21.当i达到21时,循环不再运行 。
- 增量:我们定义了i++,意思是向i加1。i值的每次变动都会引发循环的执行,直到i值等于21(就像上边讨论的那样)。在本例中,我们通过console.log()方法简单地在控制台打印出每次迭代时变量i的值。
现在让我们看看我们的猜测游戏循环 - 以下可以在resetGame()函数中找到:
var resetParas = document.querySelectorAll('.resultParas p'); for (var i = 0 ; i < resetParas.length ; i++) { resetParas[i].textContent = ''; }
此代码在<div class=“resultparas”>内使用queryselectorall()方法创建一个变量包含一个列表中的所有段落,然后依次通过每个段落,删除每个段落的文本内容。
函数的一些事
让我们再来一次最后的改进,然后再讨论。 在var resetButton下面添加以下行: 行靠近JavaScript的顶部,然后保存您的文件:
guessField.focus();
这一行使用focus()
方法立即自动地放置文本光标在输入框内,当页面加载完成时,意味着用户可以马上开始他们的第一次游戏,而不需要去点击输入框。 这只是一个小的附加,但它提高了可用性 —— 给用户提供了可视化的线索去告诉他们该怎么开始这个游戏。
让我们分析一下在这里有更多的细节。在JavaScript中,一切都是一个对象。对象是存储在单个分组中的相关功能的集合。你可以创建自己的对象,但这是相当先进的,我们现在不会谈及它,直到很晚以后的课程。现在,我们将简要讨论您的浏览器包含的内置对象,它允许您做许多有用的事情。
在这种特殊情况下,我们首先创建了一个guessField变量,用于存储对HTML中的文本输入表单字段的引用 - 在顶部附近的变量声明中可以找到以下行:
var guessField = document.querySelector('.guessField');
我们使用了document对象的querySelector()方法来获得此引用。querySelector() 需要一条信息 — — 用该元素的 CSS 选择器选择你想要的引用的元素。
因为 guessField 现在包含对 <input>的元素的引用,它现在将访问数量的属性 (存储于内部对象的其中一些不会更改其值的基础变量) 和方法 (存储在对象内部的基础函数)。一种方法可用来输入元素是 focus (),所以我们现在可以使用这条线集中文本输入︰
guessField.focus();
不包含对表单元素引用的变量不会有 focus () 方法可供它们执行。例如,guesses变量包含对 <p>元素的引用和 guessCount 包含了一个数字。
操作浏览器对象
让我们来稍微的使用一些浏览器对象。
- 首先在浏览器中打开你的程序。
- 接下来打开浏览器上的开发者工具, 并且切换到 JavaScript 控制台的标签页。
- 输入
guessField
后控制台将会显示一个包含<input>
元素的变量。你会注意到控制台能够自动补全执行环境中存在的对象的对象名,包括你的变量名! - 现在输入下面的代码:
guessField.value = 'Hello';
value
属性表示当前文本域中的值。 你能够看到输入这条指令后文本域中的值被我们改变了! - 现在试试输入
guesses
然后按下回车键。控制台会显示一个包含<p>
元素的变量。 - 现在试试输入下面这一行:
guesses.value
浏览器会返回undefined
,因为段落中并不存在value
。 - 为了改变段落中的文本内容, 你需要用
textContent
属性来代替value
。试试这个:guesses.textContent = 'Where is my paragraph?';
- 现在来一些有趣的东西。 试试一个接一个的输入下面这几行:
guesses.style.backgroundColor = 'yellow'; guesses.style.fontSize = '200%'; guesses.style.padding = '10px'; guesses.style.boxShadow = '3px 3px 6px black';
- 页面上的每个元素都有一个style属性,它本身包含一个对象,其属性包含应用于该元素的所有内联CSS样式。 这允许我们使用JavaScript在元素上动态设置新的CSS样式。
完成了...
所以这是为了建立这个例子— 你得到了结束,做得好! 尝试你的最终代码,或者看看我们的版本.如果你不能让示例工作,请检查它 source code.