循环
循环
循环体的单次执行叫作 一次迭代。
for
循环
for (begin; condition; step) {
// ……循环体……
}
// 变量 i 是在循环中声明的,这叫做“内联”变量声明
for (let i = 0; i < 3; i++) { // 结果为 0、1、2
alert(i);
}
for
循环的任何语句段都可以被省略。
let i = 0; // 我们已经声明了 i 并对它进行了赋值
for (; i < 3; i++) { // 不再需要 "begin" 语句段
alert( i ); // 0, 1, 2
}
for (; i < 3;) {
alert( i++ );
}
for (;;) {
// 无限循环
}
for..of
for..of
语句在可迭代对象(包括 Array
,Map
,Set
,String
,TypedArray
,arguments
,DOM 元素集合(比如一个NodeList
对象) 等等)上创建一个迭代循环,调用自定义迭代钩子,并为每个不同属性的值执行语句。
info
一些内置类型拥有默认的迭代器行为,其他类型(如 Object)则没有。拥有默认的 @@iterator
方法的内置类型是:
Array.prototype[@@iterator]()
TypedArray.prototype[@@iterator]()
String.prototype[@@iterator]()
Map.prototype[@@iterator]()
Set.prototype[@@iterator]()
let fruits = ["Apple", "Orange", "Plum"];
// 遍历数组元素
for (let fruit of fruits) {
alert( fruit );
}
tip
对于for..of
的循环,可以由 break
, throw
或 return
终止。
for..of
与 async..await
结合使用:
async function fn(category1List) {
for (const ele of category1List) {
if (category1CodeList.includes(ele.categoryCode)) ele.children = await this.getNextLevelList(2, ele.categoryCode)
if (Object.prototype.toString.call(ele.children) === '[object Array]') { // 判断类型,避免对undefined进行迭代报错:undefined is not iterable (cannot read property symbol(symbol.iterator)) at _iterabletoarray
for (const childrenEle of ele.children) {
if (category2CodeList.includes(childrenEle.categoryCode)) childrenEle.children = await this.getNextLevelList(3, childrenEle.categoryCode)
}
}
}
}
for..in
为了遍历一个对象的所有键(
key
),可以使用一个特殊形式的循环:for..in
。注意,所有的 “for” 结构体都允许我们在循环中定义变量,像如下的let prop
。遍历一个对象时,整数属性会被进行排序,其他属性则按照创建的顺序显示。
这里的“整数属性”指的是一个可以在不做任何更改的情况下与一个整数进行相互转换的字符串。例如:"49" 是一个整数属性名(因为我们把它转换成整数,再转换回来,它还是一样的。),但是 “+49” 和 “1.2” 就不是。
技术上来讲,因为数组也是对象,所以使用
for..in
也是可以的,但是会有一些潜在问题存在:for..in
循环会遍历所有属性(不仅仅是数组的数字属性),如果使用for..in
遍历类数组对象(类数组对象看似是数组,也就是说,它们有 length 和索引属性,但是也可能有其它的非数字的属性和方法),非数字的属性也会被遍历;for..in
循环适用于普通对象,并且做了对应的优化。但是不适用于数组,因此速度要慢 10-100 倍(当然即使是这样也依然非常快,只有在遇到瓶颈时可能会有问题)。通常来说,我们不应该用for..in
来处理数组。
使用 break
指令跳出循环
let sum = 0;
while (true) {
let value = +prompt("Enter a number", '');
if (!value) break; // 执行后立刻终止循环,将控制权传递给循环后的第一行,即alert( 'Sum: ' + sum );
sum += value;
}
alert( 'Sum: ' + sum );
使用 continue
指令继续下一次迭代
continue
不会停掉整个循环,而是停止当前这一次迭代,并强制启动新一轮循环(如果条件允许的话)。
break/continue 标签
用于一次从多层嵌套的循环中跳出来或跳转到标记循环的下一次迭代
标签 是在循环之前带有冒号的标识符
labelName: for (...) {
...
}break <labelName>
语句跳出循环至标签处outer: for (let i = 0; i < 3; i++) {
for (let j = 0; j < 3; j++) {
let input = prompt(`Value at coords (${i},${j})`, '');
// 如果是空字符串或被取消,则中断并跳出这两个循环。
if (!input) break outer; // 执行后 向上寻找名为 outer 的标签并跳出当前循环,控制权转至 alert('Done!')。
// 用得到的值做些事……
}
}
alert('Done!');continue
指令也可以与标签一起使用。在这种情况下,执行跳转到标记循环的下一次迭代。
switch
语句
switch(x) {
case 'value1': // if (x === 'value1')
...
[break]
case 'value2': // if (x === 'value2')
...
[break]
default:
...
[break]
}
比较
x
值与第一个case
(也就是value1
)是否严格相等(被比较的值必须是相同的类型才能进行匹配),然后比较第二个case
(value2
)以此类推。如果相等,
switch
语句就执行相应case
下的代码块,直到遇到最靠近的break
语句(或者直到switch
语句末尾)。如果没有符合的
case
,则执行default
代码块(如果default
存在)。如果没有
break
,程序将不经过任何检查就会继续执行下一个case
。switch
和case
都允许任意表达式。共享同一段代码的几个
case
分支可以被分为一组