3.5 教程:一个简单测验
是时候把本章学习的内容组合到一起来创建一个完整的程序了。在这个教程中,我们将创建一个简单测验系统,它提出问题并评估参加测验者的表现。首先,本节将看看可能解决这个问题的一些方式,并且讨论编程的高效技巧。
第一步总是搞清楚程序要做什么。下面是我们希望程序完成的一些事情:
询问问题。如果我们想要测验一个人,需要一种方式向他提出问题。此时,我们知道从web页面获取反馈的一种简单方法:prompt()命令。此外,我们需要一个问题列表,既然数组可以很好地用来存储信息列表,那么我们将使用数组来存储测验问题。
让测验参加者知道自己的答案是否正确。首先,需要确定测验参加者是否给出了正确答案:一个条件语句可以负责这项工作。然后,为了让测验参加者知道他的回答是正确的或错误的,可以使用alert()命令。
显示测验结果。我们需要一种方式来记录测验参加者做得有多好,只需要一个变量来记录正确回答的数目就够了。然后,为了宣布测验的最终结果,可以使用alert()命令或document.write()方法。
有很多种方法可以解决这个问题。一些程序员新手可能会采用生硬的方法,并且复制同样的代码来询问每个问题。例如,询问测验中的头两个问题的javascript可能如下所示:
这种方法似乎合乎逻辑,因为程序的目的是一个接着一个地询问问题。但是,这并不是高效的编程方式。无论何时,当你看到程序中有相同的步骤重复多次时,应该考虑使用循环或函数来替代。我们将创建一个程序把这二者都用到:使用一个循环来遍历测验中的每个问题,并且使用一个函数来执行询问问题的任务:
在文本编辑器中打开文件quiz.html。
首先,可以设置几个变量来记录正确回答的问题的数目以及测验中问题的数目。
找到页面< head>中的< script>标签之间的代码,并且输入如下代码:
这个变量存储了测验参加者回答正确的问题的数目。在测验刚开始,回答任何问题之前,我们把这个变量设置为0。接下来,可以创建问题及其答案的一个列表。
按下回车键添加新的一行,并输入var questions = [。
我们将把所有的问题存储到一个数组中,数组只不过是可以存储多个项目的一个变量。我们刚刚输入的代码是数组语句的第一部分。我们将分多行输入数组,如2.8.1节所介绍的那样。
按下回车键两次,增加两个新行,并输入];。代码如下所示:
既然测验是由一系列的问题组成,那么,把每个问题存储为数组的一个项目就有意义了。然后,当你需要询问测验问题的时候,直接遍历列表中的每个项目来提问。然而,每个问题还有一个答案,因此,我们需要一种方法来记录答案。
一个解决方案是创建另一个数组,例如answers[],它保存了所有的答案。要询问第一个问题,查找questions数组中的第一项,并且看看答案是否正确。然而,这有一个潜在的缺陷,就是两个列表可能会不同步,例如,我们在questions数组的中间位置添加了一个问题,但是却把答案放在了answers数组的开头。这时候,questions数组的第一项不再和answers数组的第一项匹配。
一种更好的替代方案是使用一个嵌套的数组或者(如果你真的想要听起来更加引人注意和令人激动的话)使用一个多维数组。这只是意味着,我们要创建一个包含问题和答案的数组,并且把这些数组作为questions数组的一个项目来存储。换句话说,我们创建了这样的列表,而其中的每个项目都是另外的一个列表。
单击[和]之间的空行,并且添加如下粗体所示的代码:
代码['how many moons does earth have?', 1]是拥有两项的一个数组。第一项是一个问题,第二项是答案。这个数组是数组questions中的第一项。我们不会给这个数组一个名字,因为它嵌套在另一个数组中。这一行末尾的逗号表示questions数组的第一项结束,而后面跟着的是另一个数组项目。
按下回车创建一个新的空白行,并把如下两行粗体代码添加到脚本中:
这一测验还有另外两个问题。注意,在数组的最后一项之后,不要输入一个逗号。在一个单个的数组中设置好所有的问题,这具有更大的灵活性。如果想要向列表添加一个问题,只要添加包含新的问题和答案的另一个嵌套的数组就可以了。
既然设置好了测验用到的基本变量,是时候搞清楚如何询问每个问题了。问题存储在一个数组中,并且我们希望询问列表中的每个问题。还记得在本书3.3.2节介绍过,循环是遍历数组中的每一项的一种理想方法。
在];(answers数组的末尾)的后面单击,按下回车键创建一个新的空行,并添加如下代码:
这一行是for循环的开始(参见3.3.3节)。它做三件事情:第一,创建一个新的名为i的变量并在其中存储数值0。这个变量是一个计数器,记录了循环迭代的次数。第二,i现在是时候进入循环的核心部分了,即每次迭代循环实际执行的javascript代码。
按下回车键创建一个新的空行,并且添加如下代码行:
我们只是运行一个函数来提问题,而不是把用来提问的所有程序代码都放入循环中。这个函数(随后创建)叫做askquestion()。每次迭代循环的时候,我们都把questions数组的一项发送到该函数,即questions[i]部分。别忘了,我们使用一个索引值来访问数组中的一项,因此,questions[0]是数组中的第一项,questions[1]是第二项,以此类推。
通过创建一个函数来提问,我们可以编写更加灵活的程序。如果需要的话,我们可以把函数移动到其他的程序中来复用。最后,我们将完成循环代码。
按下回车键创建一个新的空行,并且输入}表示循环的结束。完成后的循环代码如下所示:
是的,这就是所有的代码,只是一个简单的循环,它使用测试中每个问题来调用函数。现在,我们将创建测验的核心部分,即askquestion()函数。
在刚才添加的for循环的前面创建一个空行。
换句话说,在脚本开始定义基本变量的两条语句和刚刚添加的循环之间,添加这个函数。在脚本中任何地方定义函数都没有问题,但是,大多数程序员把函数定义放在靠近程序的开始处。在很多脚本中,像这个脚本中的score和questions那样的全局变量都先定义了,以便我们很容易看到或改变这些变量;接下来是函数,因为它们通常是构成大多数脚本的核心内容;最后是像循环这样的一步一步的操作。
添加如下的代码:
这段代码表示函数的主体;先录入一个函数的开始花括号和结束花括号,然后再在其中添加脚本,这是一个不错的办法。通过这种方式,我们不会偶然忘记添加结束花括号。
这个函数接受一个单个的参数并且将其存储在一个名为question的变量中。注意,这和我们在步骤6中所创建的questions[]数组不同。在这个例子中,question变量实际上是使用questions[]数组中的一项来填充的。正如我们在步骤8中所见到的,数组中的一项实际上是包含两项的另一个数组,这两项是question和answer。
添加如下粗体所示的代码:
这看上去有些似曾相识,这是prompt()命令。唯一可能觉得比较新的部分就是question[0]。这是访问question数组的第一项。在这个例子中,这个函数接受一个数组,它包含一个问题和一个答案:例如,第一个数组是['how many moons does earth have?', 1]。因此,question[0]访问了第一项,即'how many moons does earth have',它传递给prompt()命令,作为将要出现在提示对话框中的问题。
我们的程序把测验参加者在提示框中输入的内容添加到变量answer中。接下来,我们将把测验参加者的回答和问题的实际答案进行比较。
通过添加如下所示的粗体代码来完成函数:
这段代码只是一条基本的if/else语句。条件answer == question[1]检查用户输入(回答)的是否和答案相同,答案则存储在数组的第二项(question[1])中。如果匹配,那么测验参加者答对了:显示一条警告信息让参加者知道答对了,并且他的分数增加1(score++)。当然,如果他没有答对,一条消息会给出正确的答案。
此时,测验功能完整了。如果保存文件并在web浏览器中载入它,我们将能够进行测验。然而,我们还没有为测验参加者提供结果,以便他知道答对了多少问题。我们将在web页面的< body>中添加一段脚本,以显示结果。
找到靠近web页面底部的第二对< script>标记,在其中输入如下代码:
这里,我们创建了一个新的变量并把字符串“you got”以及测验参加者的分数存储到其中。因此,如果他答对了3个问题,变量message将会是“you got 3”。为了让脚本更容易阅读,我们将用数行代码来构建一条更长的消息。
按下回车键并输入如下代码:
这会向消息字符串中添加“out of”以及问题的总数,因此,此时,消息会像“you got 3 out of 3”这样。现在,完成消息并将其显示到屏幕。
把代码中粗体显示的行添加到脚本中:
保存页面并在web浏览器中打开它。进行测验,并看看能够做到多好(如图3-10所示)。如果这个脚本不工作,请参考1.6节提到的一些排错技术。我们也可以把这个脚本和complete_quiz.html文件中完整的、功能完备的版本做比较。
尝试在脚本的开始处向questions[]数组中添加几个问题,以便测验能够更长。
既然我们已经学习了javascript中并不令人兴奋且颇费脑筋的细节,是时候把注意力转向真正的乐趣了。在第二部分中,我们将学习jquery,了解jquery是什么,如何使用它,还有最重要的,如何通过javascript编程享受乐趣和完成实际任务。