JavaScript/控制结构
大多数编程语言都由“积木”组成,例如标记(关键字、变量、运算符等)、表达式(例如 myArray.length + 1
)、语句(用 ;
分隔)、块 {...}
、函数和模块。乍一看,程序的执行遵循语句的顺序,从上到下。但在几乎所有情况下,程序都需要不按语句的严格顺序运行。相反,某些部分必须仅在满足特定条件时才运行,而其他部分将被省略并在不同的条件下运行。或者,可能需要某些部分重复执行。其他部分可能会并行运行,并在稍后同步。或者,不同模块的函数必须计算出值,然后才能执行下一个语句。
在这个“语言积木”的层次结构中,术语 **块** 对于理解程序流程至关重要。在 JavaScript 中,块是零个或多个语句(或较小的块)的序列,这些语句被大括号包围 { // 零个或多个语句 }
。我们在这里讨论的语言结构会调用或重复块。
if / else
语句(是的,它是一个单一语句,即使它在其块中包含其他语句)会根据条件的评估结果调用两个块之一的执行。评估返回一个 布尔值。如果为 true
,则执行第一个块;如果为 false
,则执行第二个块。另一个块将被跳过。
if ( condition ) {
// block of statements
} else {
// block of statements
}
else
部分是可选的,即可以使用 if
而没有 else
部分及其块。
if ( condition ) {
// block of statements
}
一个例子
"use strict";
const a = 3;
const b = "3";
if (a == b) {
alert("The two variables contain the same value, but may have different data types.");
} else {
alert("The two variables contain different values.");
}
// an example without 'else'
const c = 6 / 2;
if (a === c) {
alert("The two variables contains the same value and are of the same data type.");
}
如果两个块之一正好包含一条语句,则可以省略大括号。但为了代码清晰起见,我们建议使用带有大括号的统一语法。
// same as above; but this abbreviated syntax is not recommended.
"use strict";
const a = 3;
const b = "3";
if (a == b) alert("The two variables contains the same value, but may have different data types.");
else alert("The two variables contain different values.");
const c = 6 / 2;
if (a === c) alert("The two variables contains the same value and are of the same data type.");
在很多情况下,实际情况需要比简单的真/假替代更复杂的决策。例如,您可能想知道一个数字是负数、零还是正数。在这种情况下,解决方案可能如下所示
"use strict";
const x = 3;
if (x < 0) {
alert("The number is negative.");
} else {
// x is equal or greater than 0
if (x === 0) {
alert("The number zero.");
} else {
alert("The number is positive.");
}
}
您可以缩短这段代码,而不会失去清晰度。因为第一个 else
块仅包含一条语句 - 即第二个 if
- 您可以省略其大括号并将第一个 else
和第二个 if
合并为一行。
"use strict";
const x = 3;
if (x < 0) {
alert("The number is negative.");
} else if (x === 0) {
alert("The number is zero.");
} else {
alert("The number is positive.");
}
这是一个清晰且经常使用的编程风格。它用于您有可管理的选项数量或必须使用多个变量进行决策的情况。
如果决策数量大幅增加,则使用 switch
语句而不是长长的 else if
条件列表会使代码更清晰。
switch
语句会评估表达式,并根据其结果与 case
关键字后面的标签的比较来引导语句的流程。
"use strict";
const myVar = "a";
// evaluation takes simple variables as well as complex expressions
switch (myVar.toUpperCase()) {
case "A":
// …
break;
case "B":
// …
break;
default: // analog to 'else' without any further 'if'
// …
break;
}
如果评估结果与其中一个标签匹配,JavaScript 会执行从下一个 break
或整个 switch
的末尾开始的以下语句。如果没有任何标签匹配,则执行会继续在 default
标签处,或者 - 如果不存在 - 完全跳过 switch
语句。
标签是字面量或表达式;例如,case (2 + 1).toString():
是可能的。
一旦遇到 break
语句,switch
的执行就会终止。通常它出现在每个 case 的末尾,以防止执行以下 case 的代码。但如果故意要执行它们,则可以省略它。在以下示例中,相同的代码将针对 i
等于 1、2 或 3 运行。
"use strict";
const i = 2;
switch(i) {
case 1:
case 2:
case 3:
// …
break;
case 4:
// …
break;
default:
// …
break;
}
因为要评估的表达式以及标签可以是复杂的表达式,所以可以构建非常灵活的结构。
"use strict";
const i = 2;
switch(true) { // in this example it's a constant value
case (i < 10):
alert("one digit");
break;
case (i >= 10 && i < 100):
alert("two digits");
break;
default:
// …
break;
}
continue
关键字不适用于 switch
语句。
如果存在运行时错误可能发生的可能性,您可以“捕获”该错误并执行有意义的操作来处理这种情况。例如,网络连接或数据库可能不再可用;用户输入导致零除;… .
try {
// critical block where errors might occur
} catch (err) {
// block to handle possible errors. Normally not executed.
} finally {
// block that will be executed in ALL cases
}
"use strict";
const x = 15;
let average;
try {
// block with critical statements
x = x + 5;
average = x / 0;
alert("The average is: " + average);
} catch (err) {
// block to handle possible errors
alert("Something strange occurs. The error is: " + err);
} finally {
// block that will be executed in ALL cases
alert("End of program.");
}
如果 关键 块中的某个语句引发运行时错误,则会省略其剩余语句的执行。相反,执行会调用 catch 块。最后,执行 finally 块。
请注意,finally 块在所有情况下都会执行,无论是否发生运行时错误。这甚至适用于 关键 或 catch 块执行 return
语句的情况。
在上面的示例中,JavaScript 引擎会自行抛出异常。在其他情况下,JavaScript 引擎以某种方式或其他方式进行操作,但您可能希望看到它以不同的方式处理。例如,在零除的情况下,引擎不会抛出错误;它会将 Infinity
分配给结果,并跳到下一条语句。如果您想要不同的行为,则可以创建和抛出自己的程序异常。
"use strict";
const x = 15;
let average;
try {
// block with critical statements
average = x / 0;
// or: const z = "abc"; average = z / 0;
if (average === Infinity || Number.isNaN(average)) {
// Throw your own exception with any text
throw "Error during division. The result is: " + average;
}
alert("The average is: " + average);
} catch (err) {
// block to handle possible errors
alert("Something strange occurs. The error is: " + err);
} finally {
// block that will be executed in ALL cases
alert("End of program.");
}
如果发生异常 - 由 JavaScript 引擎或您的程序生成,并且没有被 catch 块捕获 - 脚本会终止,或者 - 如果它是函数 - 它会将控制权返回给调用函数。错误处理可以在那里或在调用它的函数之一中实现。
"use strict";
const answer = prompt("How old are you?");
const age = Number(answer);
if (isNaN(age)) {
throw answer + " cannot be converted to a number.";
// The script terminates with this message (it's not a function)
}
alert("Next year you will be " + (age + 1));
循环和迭代是其他情况,在这些情况下,语句的顺序流程由周围的语言结构进行操作。这将在下一页中进行描述。