2.3 在JavaScript中进行判定
判定(decision making)赋予了程序智能。不使用它你就不能写出一个好的程序,不管是创建游戏、校验密码、根据用户前面做出的选择给予用户一组选择,还是一些其他的情况。
判定是以条件语句为基础的,条件语句是一种值或真或假的简单语句。这就是基本数据类型中的布尔(Boolean)数据类型该应用的地方了。循环是进行判定的另一个重要工具,例如,可以从头到尾地循环用户的输入或循环一个数组,并作出对应的决策。
2.3.1 逻辑运算符和比较运算符
有2组主要的运算符,我们会学到下面的内容。
l 数据比较运算符(data comparision operator):比较操作数并返回布尔值。
l 逻辑运算符(logical operator):对多于一种条件的情况进行测试。
我们先看一下比较运算符。
1.数据比较
表2-3列出了一些最常用的比较运算符。
表2-3 JavaScript中的比较运算符
|
运算符 |
描 述 |
例 子 |
|
== |
检查左边和右边的操作数是否相等 |
123 == 234 返回假值 123 == 123 返回真值 |
|
!= |
检查左边与右边的操作数是否不相等 |
123 != 123 返回假值 123 != 234 返回真值 |
|
> |
检查左边的操作数是否大于右边的操作数 |
123 > 234 返回假值 234 > 123 返回真值 |
|
>= |
检查左边的操作数是否大于或等于右边的操作数 |
123 >= 234 返回假值 123 >= 123 返回真值 |
|
< |
检查左边的操作数是否小于右边的操作数 |
234 < 123 返回假值 123 < 234 返回真值 |
|
<= |
检查左边的操作数是否小于或等于右边的操作数 |
234 <= 123 返回假值 234 <= 234 返回真值 |
警告 小心这个==相等运算符:很容易在脚本中由于被误用为赋值运算符“=”而产生许多错误。
这些运算符常与字符串类型数据和数字类型一起使用,并且是区分大小写的:


下面是得到的结果:
![]()
当计算一个字符串比较的表达式时,JavaScript解释器会依次比较两个字符串中每个字符的ASCII码——每个字符串的第一个字符,然后是第二个字符,依此类推。大写的A在ASCII中表示65,B表示66,C表示67,依此类推。计算这个表达式"Apple" < "Banana",JavaScript解释器使用每个字符中的第一个字符的ASCII码来进行比较:65 < 66,因此A排在前面,这个比较是真值。当检验这个表达式"apple"<"Banana"的时候,JavaScript解释器做了同样的事情;然而,小写字母a的ASCII码是97,因此这个表达式"a" < "B"转变为97 < 66,它的值是假。可以使用<、<=、>、>= 运算符来进行字母顺序的比较。如果需要确保所有的字母都是同样的大写或小写,可以使用String对象的toUpperCase()和toLowerCase()方法。比较运算符和数字运算符是一样的,都可以使用变量。如果想按字母顺序比较apple和Banana,可以这样做:

可是在使用等号运算符比较String对象的时候,有一些细节需要注意。试一下这个:

你会得到一个返回false值。事实上,我们在上面比较的是两个String对象,而不是两个基本类型的字符串包含的字符。返回的false结果表明,即使两个字符串对象持有相同的字母,它们也不是同一个对象。
如果你确实需要比较两个对象持有的字符串,可以使用valueOf()方法来对数据值进行比较:

2.逻辑运算符
有时候需要把多个比较放到一个条件组中。你也许想检查用户输入的信息是否有意义,或者根据用户前面的回答,限制他们可以选择的数据项。可以使用表2-4中的逻辑运算符来完成这样的功能。
表2-4 JavaScript中的逻辑运算符
|
符 号 |
运算符 |
描 述 |
例 子 |
|
&& |
与 |
两个条件都必须为真 |
123 == 234 && 123 < 20 (false) 123 == 234 && 123 == 123 (false) 123 == 123 && 234 < 900 (true) |
|
|| |
或 |
其中一个或两个必须为真 |
123 == 234 || 123 < 20 (false) 123 == 234 || 123 == 123 (true) 123 == 123 || 234 < 900 (true) |
|
! |
非 |
原逻辑取反 |
!(123 == 234) (true) !(123 == 123) (false) |
一旦求出了数据的值,我们需要能够根据这个输出结果进行判定选择。这正是条件语句和循环语句可以发挥作用的地方。你会发现本章中介绍的运算符会经常用到条件语句或循环语句中。
2.3.2 条件语句
if...else结构用来测试条件,格式如下:

如果这个条件测试为真,紧跟if后面的大括号中的代码就会被执行,但如果它不为真则不会执行。也可以使用else语句,创建在if条件不满足的情况下应该执行的代码块。
我们来改进一下在本章前面建立的货币转换程序,创建一个循环来处理用户的非数字输入:


这个if语句使用了isNaN()函数,如果变量eurosToConvert中的值不是一个数它会返回true。
注解 记住尽可能地使错误信息友好并且有用。良好的错误信息可以明晰地告知用户他们该做什么,这样可以使他们更有耐心地使用应用程序。
使用逻辑运算符和嵌套的if语句,可以创建更复杂的条件:


我们知道这个数只要是一个数字并且小于10就可以。
注解 注意这段代码的布局。我们对if与else语句以及代码块使用了缩进,所以非常容易阅读和理解代码块是从哪里开始和结束的。使你的代码尽可能简单明了是非常重要的。
试着阅读一下没有使用缩进和空格的这段代码:

它不是不能阅读,但是即使在这个简短的脚本中,也很难分辨出哪个代码块属于if和else语句。在更长的代码中,不一致或不合理的缩进使代码很难读懂,它反过来会留给你更多的需要修正的漏洞且使你的工作不必要地更困难。
也可以在另一个以if语句开始的else语句的地方使用else if语句,像下面这样:



这段代码和前面的代码段完成同样的事情,但是使用了一个else if语句代替一个嵌套的if语句,并且代码少了两行。
跳出一个分支或循环
在继续之前需要注意一件事情:可以使用break语句来中断一个条件语句或循环。它简单地中断了代码块的运行并且使进程跳到下一语句。我们会在下一个例子中用到它。
只要你喜欢,可以使用许多的if、else和else if语句,尽管过多使用会使代码十分复杂。如果在一个代码块中检查一个值有许多可能的条件,那么我们接下来会看到的switch语句将非常有用。
2.3.3 测试多个值:switch语句
switch语句允许根据一个变量或表达式的值在多个代码段之间进行“转换”。下面是一个switch语句的概要格式:

JavaScript计算switch (expression)的值,然后把它与每个case进行比较。只要发现了一个匹配的项,代码就会在那个位置开始执行,并继续遍历执行所有的case语句直到发现了一个break语句。如果没有一个case语句匹配,最好包含一个默认的情况。以用于尽快找出错误发生的地方,例如,我们期望一种情况被满足,但是一个程序bug阻止了它发生。
case的值可以是任何数据类型,例如数字或字符串。可以根据自己的需要选择一个或多个case语句。下面来看一个简单的示例:

运行它。你只会得到自己刚输入的数字或者这个句子“Please enter a numeric value between 1 and 4.”。
这个示例也阐明了break语句的重要性。如果我们在每个case语句后不包括break,那么这个代码块中的代码会继续执行直到最后switch结束。试一下去掉所有的break然后输入2。匹配项后的所有代码都会执行,因此给你这样一个输出结果:
![]()
可以在switch语句中使用任何有效的表达式,例如一个计算:
![]()
也可以在case语句间使用一个或多个语句。
2.3.4 重复事件:循环
在本节中,我们会学习只要一组条件为真如何重复一个代码块。举个例子,我们可能需要循环一遍HTML表单中的每个输入或者循环遍历一个数组中的每个元素。
1.重复一个集合多次:for循环
for循环用来循环一个代码块许多次,格式如下:

和条件语句类似,关键字for后紧跟着括号。这次,括号中包含由分号分割的三部分。
第一部分初始化一个变量,它用来当作保存循环次数的计数器。第二部分测试条件。只要这个条件为真,循环就会继续运行。最后一个部分在每遍循环之后增加或减少这个在第一部分中创建的计数(事实上你会发现这个之后在编程中很重要)。
例如,看一下这个循环,只要loopCounter小于等于10,它就会继续运行:
![]()
只要循环条件为真,循环就会继续执行——正如只要loopCounter小于或等于10。一旦它达到了11,这个循环就会终止并且代码的执行会从loop的结束括号后面的下一个语句开始。
让我们来看一个使用for循环来遍历一个数组的示例。我们会使用一个for循环来遍历一个叫做theBeatle的数组,它使用一个叫loopCounter的变量。当loopCounter的值小于数组的长度时,循环就会继续执行:


这个例子可以运行因为我们使用了一个从零开始计数的数组,在它里面数据项按顺序被添加到索引上。如果使用了按如下方式来保存数据项的关键字,那么这个循环就不会执行了:
![]()
在前面讲述数组的时候,我强调了Array对象有一个知道数组长度的属性(有多少个元素)。当循环遍历数组的时候,如前面的例子,我们使用了数组名后跟一个点和length作为条件。它阻止了循环数到数组的长度以外去,这样会造成一个“越界”的错误。
JavaScript也支持for..in循环(尽管IE从IE 5才开始支持它,但它从NN 2就开始到处使用了)。不再使用计数器,for...in循环使用访问数组的变量来遍历数组中的每个元素:

在循环的每一遍中,关键字indexKey会与数组中按照同样顺序使用关键字取出的值一起输出:

2.依据一个条件判定重复执行动作脚本:while循环
目前我们所接触的循环都是从脚本自身的内部获取停止循环的指令。可能存在多次这样的情况,你想让用户决定循环应该何时停止,或者当一个用户决定的条件满足的时候停止循环。循环 while和do...while正是用来解决这类问题的。
while循环最简单的形式如下所示:
![]()
括号里的条件可以是你在一个if语句当中可能会使用到的任何内容。按下面的方式使用代码,它允许用户输入数字并且在输入数字99后停止输入的程序。


在这里while循环的条件是userInput不等于99,所以只要这个条件为真,循环就会继续。当用户输入99并且条件被检验的时候,它会计算得到假值并且循环会终止。注意用户输入99后,循环不会立即终止,只有当条件在循环的另一遍开始处被再次检验时,循环才会终止。
在while和do...while循环之间,有一个比较小但非常明显的不同之处:while循环在代码执行前检验条件,并且只有在条件为真的情况下才会执行代码块。而do...while在检验条件之前执行代码块,如果条件为真会执行另一遍循环。简而言之,do...while循环在条件检查前循环体中的代码至少会执行一次。可以如下所示,使用一个do...while循环来写一个前面的例子:


不需要初始化userInput,因为循环中的代码在第一次检验它之前已经为它设置了一个值。
3.继续循环
你已经看到了,break语句用于只要某个特定的事件发生就跳出任一类型的循环。这个continue关键字的工作原理和break类似,可以用来停止循环的执行。可是,continue语句不是直接地跳出循环,而是在下一次循环遍历中使代码重新开始执行。
首先改变一下前面的例子,使用break来达到这样的一种效果,如果用户没有输入一个数字而是输入了其他的,那么这个输入的值不会被记录并且循环会终止。

现在再把它改变一下,使用continue语句,可以不让它跳出循环,而是忽略用户的输入并保持循环。
![]()


break语句已被continue替换了,因此在循环中的代码不会执行了,但是while语句中的条件会再次执行。如果条件为真,循环的另一个遍历就会被触发执行;否则这个循环就结束了。
使用下面的经验规则来决定使用哪一种循环结构:
l 如果想重复一个动作一定的次数,那么使用for循环。
l 当你想一个动作被重复执行直到满足某个条件的时候,使用while循环。
l 如果想保证这个动作至少被执行一次,那么使用do...while循环。






