语句
if
语句
if
语句的格式如下:
if (statement_A) {
statements;
} else if (statement_B) {
statements;
} else {
statements;
}
注意,JavaScript 语言规定,else
总是和它上面最近的一个 if
配对,这与 C 语言一致。因此,类似于if (A) if (B) C; else D;
形式的语句应该理解为:
if (A)
if (B)
C;
else
D;
switch
语句
switch
语句的格式如下:
switch (控制表达式) {
case 表达式:
语句列表
case 表达式:
语句列表
...
default
常量表达式: 语句列表
}
switch
语句使用 ===
判断控制表达式的值是否和某个常量表达式相等。分支的表达式可以相同,程序不会因此马上抛出错误。如果控制表达式不等于任何一个常量表达式,则从default
分支开始执行,通常把default
分支写在最后,但不是必需的。
使用 switch
语句要注意以下几点:
- 进入
case
后如果没有遇到break
语句就会一直往下执行,后面其他case
或default
分支的语句也会被执行到,直到遇到break
,或者执行到整个switch
语句块的末尾。通常每个case
后面都要加上break
语句,但有时会故意不加break
,例如在函数体中使用switch
语句,用return
代替break
。 - 与 C 语言不同,JavaScript
case
后面的表达式可以不是常量表达式,表达式的值也可以不是整型。ECMAScript 标准允许case
子句后面可以有任意表达式。 default:
标签通常出现在switch
语句的末尾,这只是一个逻辑上通用的地方,实际上它可以出现在语句主体内的任何位置。
switch
语句不是必不可少的,显然可以用一组 if...else if...else if...else...
代替,但是一方面用 switch
语句会使代码更清晰。
while
语句
initialize;
while(test){
statements;
increment;
}
例如:
let count = 0;
while(count < 10) {
console.log(count);
count++;
}
变量count
是循环变量(Loop Variable),每次循环都要改变它的值,在控制表达式中要测试它的值,这两点合起来起到控制循环次数的作用,在这个例子
中的值是递减的,也有些循环采用递增的循环变量。
do/while
语句
initialize;
do{
statements;
increment;
}while(test)
for
语句
for (initialize; test; increment) {
statement
}
for
循环的语法格式等价于 while
循环的语法格式,从这种等价的形式来看,initialize
表达式和increment
表达式都可以为空,但test
表达式是必不可少的。例如
for (;1;){...}
// 等价于
while(1){...}
因此,ECMAScript 标准规定,如果test
表达式为空,则认为test
表达式的值为真,因此死循环也可以写成
for (;;){...}
for/of
语句
ES6 定义了一个新的循环语句:for/of
。这种新的循环使用 for
关键字,但是与常规的 for
循环完全不同。for/of
循环适用于可迭代对象。
let data = [1, 2, 3, 4, 5, 6, 7, 8, 9], sum = 0;
for(let element of data) {
sum += element;
data.push(sum)
}
sum // => 45
goto
语句和异常处理
goto
语句可以实现无条件跳转。我们知道break只能跳出最内层的循环,如果在一个嵌套循环中遇到某个错误条件需要立即跳出最外层循环做出错处理,就可以用goto
语句,例如:
for (...){
for (...){
...
if (出现错误条件)
goto error;
}
}
error:
出错处理;
这里的error:
叫作标号(Label),任何语句前面都可以加若干个标号,每个标号的命名也要遵循标识符的命名规则。
goto
语句过于强大了,从程序中的任何地方都可以无条件跳转到任何其他地方,只要在那个地方定义一个标号就行,唯一的限制是goto
只能跳转到同一个函数
中的某个标号处,而不能跳到别的函数中。滥用goto
语句会使程序的控制流程非常复杂,可读性很差。著名的计算机科学家 Edsger W.Dijkstra 最早指出编程语
言中goto
语句的危害,提倡取消goto
语句。goto
语句不是必须存在的,显然可以用别的办法替代,比如上面的代码段可以改写为以下形式:
int cond = 0; /* bool variable indicating error condition */
for (...){
for (...){
...
if (出现错误条件){
cond = 1;
break;
}
}
if (cond)
break;
}
if (cond)
错误处理;
通常goto
语句只用于这种场合,一个函数中任何地方出现了错误条件都可以立即跳转到函数末尾进行出错处理(例如释放先前分配的资源、恢复先前改动过的
全局变量等),处理完之后函数返回。比较用goto
和不用goto
的两种写法,用goto
语句还是方便很多。但是除此之外,在任何其他场合都不要轻易考虑使用goto
语句。
有些编程语言 (如 C++) 中有异常(Exception)处理的语法,可以代替goto
和setjmp
/longjmp
的这种用法。case
和default
后面也要跟冒号:
,事实上它们是两种特殊的标号。
C标准库函数
setjmp
和longjmp
配合起来可以实现函数间的跳转,但只能从被调用的函数跳回到它的直接或间接调用者(同时从栈空间弹出一个或多个栈顿),而不能从一个函数跳转到另一个和它毫不相干的函数中。setjmp/longjmp
函数主要也是用于出错处理,比如函数A
调用函数B
,函数B
调用函数C
,如果在C
中出现某个错误条件,使得函数B
和C
继续执行下去都没有意义了,可以利用setjmp/longjmp
机制快速返回到函数A
进行出错处理,本书不详细介绍这种机制,有兴趣的读者可参考《Advanced Programming in the UNIX Environment》的第7.10节和第10.15节。