break 和 continuebreakbreak 加标签:退出任何带标签的语句continueif 语句 [ES1]if 语句的语法switch 语句 [ES3]switch 语句的第一个示例return 或 break!default 子句检查非法值while 循环 [ES1]while 循环的示例do-while 循环 [ES3]for 循环 [ES1]for 循环的示例for-of 循环 [ES6]const:for-of 与 forfor-await-of 循环 [ES2018]for-in 循环(避免使用) [ES1]本章涵盖以下控制流语句
if 语句 [ES1]switch 语句 [ES3]while 循环 [ES1]do-while 循环 [ES3]for 循环 [ES1]for-of 循环 [ES6]for-await-of 循环 [ES2018]for-in 循环 [ES1]break 和 continuebreak 和 continue 这两个运算符可用于在我们位于循环和其他语句内部时控制它们。
breakbreak 有两种版本:一种带操作数,一种不带操作数。后者版本适用于以下语句:while、do-while、for、for-of、for-await-of、for-in 和 switch。它立即退出当前语句
for (const x of ['a', 'b', 'c']) {
console.log(x);
if (x === 'b') break;
console.log('---')
}
// Output:
// 'a'
// '---'
// 'b'break 加标签:退出任何带标签的语句带操作数的 break 可以在任何地方使用。其操作数是一个*标签*。标签可以放在任何语句的前面,包括块。break my_label 退出标签为 my_label 的语句
my_label: { // label
if (condition) break my_label; // labeled break
// ···
}在以下示例中,搜索可以
result。这在循环之后直接处理(B 行)。result。然后我们使用 break 加标签(A 行)来跳过处理失败的代码。function findSuffix(stringArray, suffix) {
let result;
search_block: {
for (const str of stringArray) {
if (str.endsWith(suffix)) {
// Success:
result = str;
break search_block; // (A)
}
} // for
// Failure:
result = '(Untitled)'; // (B)
} // search_block
return { suffix, result };
// Same as: {suffix: suffix, result: result}
}
assert.deepEqual(
findSuffix(['notes.txt', 'index.html'], '.html'),
{ suffix: '.html', result: 'index.html' }
);
assert.deepEqual(
findSuffix(['notes.txt', 'index.html'], '.mjs'),
{ suffix: '.mjs', result: '(Untitled)' }
);continuecontinue 仅适用于 while、do-while、for、for-of、for-await-of 和 for-in。它立即退出当前循环迭代并继续下一个迭代 – 例如
const lines = [
'Normal line',
'# Comment',
'Another normal line',
];
for (const line of lines) {
if (line.startsWith('#')) continue;
console.log(line);
}
// Output:
// 'Normal line'
// 'Another normal line'if、while 和 do-while 具有原则上为布尔值的条件。但是,条件只需为*真值*(如果强制转换为布尔值为 true)即可被接受。换句话说,以下两个控制流语句是等效的
if (value) {}
if (Boolean(value) === true) {}这是所有*假值*的列表
undefined、nullfalse0、NaN0n''所有其他值都是真值。有关更多信息,请参阅 §15.2 “假值和真值”。
if 语句 [ES1]这是两个简单的 if 语句:一个只有“then”分支,另一个同时具有“then”分支和“else”分支
if (cond) {
// then branch
}
if (cond) {
// then branch
} else {
// else branch
}else 可以后跟另一个 if 语句,而不是块
if (cond1) {
// ···
} else if (cond2) {
// ···
}
if (cond1) {
// ···
} else if (cond2) {
// ···
} else {
// ···
}您可以使用更多 else if 继续此链。
if 语句的语法if 语句的一般语法是
if (cond) «then_statement»
else «else_statement»到目前为止,then_statement 一直是一个块,但我们可以使用任何语句。该语句必须以分号结尾
if (true) console.log('Yes'); else console.log('No');这意味着 else if 不是它自己的构造;它只是一个 if 语句,其 else_statement 是另一个 if 语句。
switch 语句 [ES3]switch 语句如下所示
switch («switch_expression») {
«switch_body»
}
switch 的主体由零个或多个 case 子句组成
case «case_expression»:
«statements»
以及可选的 default 子句
default:
«statements»
switch 的执行方式如下
switch 语句的第一个示例让我们看一个例子:以下函数将 1-7 之间的数字转换为星期几的名称。
function dayOfTheWeek(num) {
switch (num) {
case 1:
return 'Monday';
case 2:
return 'Tuesday';
case 3:
return 'Wednesday';
case 4:
return 'Thursday';
case 5:
return 'Friday';
case 6:
return 'Saturday';
case 7:
return 'Sunday';
}
}
assert.equal(dayOfTheWeek(5), 'Friday');return 或 break!在 case 子句的末尾,执行将继续执行下一条 case 子句,除非我们使用 return 或 break – 例如
function englishToFrench(english) {
let french;
switch (english) {
case 'hello':
french = 'bonjour';
case 'goodbye':
french = 'au revoir';
}
return french;
}
// The result should be 'bonjour'!
assert.equal(englishToFrench('hello'), 'au revoir');也就是说,我们对 dayOfTheWeek() 的实现之所以有效,是因为我们使用了 return。我们可以通过使用 break 来修复 englishToFrench()
function englishToFrench(english) {
let french;
switch (english) {
case 'hello':
french = 'bonjour';
break;
case 'goodbye':
french = 'au revoir';
break;
}
return french;
}
assert.equal(englishToFrench('hello'), 'bonjour'); // ok可以省略 case 子句的语句,这实际上为我们提供了每个 case 子句的多个 case 表达式
function isWeekDay(name) {
switch (name) {
case 'Monday':
case 'Tuesday':
case 'Wednesday':
case 'Thursday':
case 'Friday':
return true;
case 'Saturday':
case 'Sunday':
return false;
}
}
assert.equal(isWeekDay('Wednesday'), true);
assert.equal(isWeekDay('Sunday'), false);default 子句检查非法值如果 switch 表达式没有其他匹配项,则跳转到 default 子句。这使得它对错误检查很有用
function isWeekDay(name) {
switch (name) {
case 'Monday':
case 'Tuesday':
case 'Wednesday':
case 'Thursday':
case 'Friday':
return true;
case 'Saturday':
case 'Sunday':
return false;
default:
throw new Error('Illegal value: '+name);
}
}
assert.throws(
() => isWeekDay('January'),
{message: 'Illegal value: January'}); 练习:
switch
exercises/control-flow/number_to_month_test.mjs
exercises/control-flow/is_object_via_switch_test.mjswhile 循环 [ES1]while 循环具有以下语法
while («condition») {
«statements»
}
在每次循环迭代之前,while 都会评估 condition
while 主体将再次执行。while 循环的示例以下代码使用 while 循环。在每次循环迭代中,它都通过 .shift() 删除 arr 的第一个元素并记录它。
const arr = ['a', 'b', 'c'];
while (arr.length > 0) {
const elem = arr.shift(); // remove first element
console.log(elem);
}
// Output:
// 'a'
// 'b'
// 'c'如果条件始终评估为 true,则 while 是一个无限循环
while (true) {
if (Math.random() === 0) break;
}do-while 循环 [ES3]do-while 循环的工作方式与 while 非常相似,但它在每次循环迭代*之后*检查其条件,而不是之前。
let input;
do {
input = prompt('Enter text:');
console.log(input);
} while (input !== ':q');do-while 也可以看作是至少运行一次的 while 循环。
prompt() 是一个在 Web 浏览器中可用的全局函数。它提示用户输入文本并返回它。
for 循环 [ES1]for 循环具有以下语法
for («initialization»; «condition»; «post_iteration») {
«statements»
}
第一行是循环的*头部*,它控制*主体*(循环的其余部分)执行的次数。它包含三个部分,每个部分都是可选的
initialization:为循环设置变量等。此处通过 let 或 const 声明的变量仅存在于循环内部。condition:在每次循环迭代之前检查此条件。如果为假,则循环停止。post_iteration:每次循环迭代后执行此代码。因此,for 循环大致等效于以下 while 循环
«initialization»
while («condition») {
«statements»
«post_iteration»
}
for 循环的示例例如,以下是通过 for 循环从零计数到二的方法
for (let i=0; i<3; i++) {
console.log(i);
}
// Output:
// 0
// 1
// 2以下是通过 for 循环记录数组内容的方法
const arr = ['a', 'b', 'c'];
for (let i=0; i<arr.length; i++) {
console.log(arr[i]);
}
// Output:
// 'a'
// 'b'
// 'c'如果我们省略头部的所有三个部分,我们将得到一个无限循环
for (;;) {
if (Math.random() === 0) break;
}for-of 循环 [ES6]for-of 循环迭代任何*可迭代对象* – 支持 *迭代协议* 的数据容器。每个迭代值都存储在一个变量中,如头部中指定的那样
for («iteration_variable» of «iterable») {
«statements»
}
迭代变量通常通过变量声明创建
const iterable = ['hello', 'world'];
for (const elem of iterable) {
console.log(elem);
}
// Output:
// 'hello'
// 'world'但我们也可以使用已经存在的(可变)变量
const iterable = ['hello', 'world'];
let elem;
for (elem of iterable) {
console.log(elem);
}const:for-of 与 for请注意,在 for-of 循环中,我们可以使用 const。迭代变量对于每次迭代仍然可以不同(它只是在迭代过程中不能更改)。将其视为每次都在新的作用域中执行新的 const 声明。
相反,在 for 循环中,如果变量的值发生变化,我们必须通过 let 或 var 声明变量。
如前所述,for-of 适用于任何可迭代对象,而不仅仅是数组 – 例如,集
const set = new Set(['hello', 'world']);
for (const elem of set) {
console.log(elem);
}最后,我们还可以使用 for-of 迭代数组的 [索引,元素] 条目
const arr = ['a', 'b', 'c'];
for (const [index, elem] of arr.entries()) {
console.log(`${index} -> ${elem}`);
}
// Output:
// '0 -> a'
// '1 -> b'
// '2 -> c'使用 [index, element],我们正在使用 *解构* 来访问数组元素。
练习:
for-of
exercises/control-flow/array_to_string_test.mjs
for-await-of 循环 [ES2018]for-await-of 类似于 for-of,但它适用于异步可迭代对象,而不是同步可迭代对象。并且它只能在异步函数和异步生成器中使用。
for await (const item of asyncIterable) {
// ···
}异步迭代章节 中详细描述了 for-await-of。
for-in 循环(避免使用) [ES1]for-in 循环访问对象的 all(自身和继承的)可枚举属性键。当循环遍历数组时,它很少是一个好的选择
以下代码演示了这些要点
const arr = ['a', 'b', 'c'];
arr.propKey = 'property value';
for (const key in arr) {
console.log(key);
}
// Output:
// '0'
// '1'
// '2'
// 'propKey'for-await-of。for-of。请注意,数组是可迭代的。.forEach()。for 循环来循环遍历数组。for-in 来循环遍历数组。 测验
请参阅 测验应用程序。