ECMA-262 描述了一些语句(也称为流控制语句),用来完成逻辑任务。
if
if (condition) {
console.log("Greater than 25.");
} else if (i < 0) {
console.log("Less than 0.");
} else {
console.log("Between 0 and 25, inclusive.");
}
这里的条件(condition)可以是任何表达式。ECMAScript 会自动调用 Boolean()函数将这个表达式的值转换为布尔值。
单行时可以省略{},但最好不省略。
do while
do-while 语句是一种后测试循环语句,一次循环结束后才进行条件判断。所以循环体内代码在退出前至少要执行一次。
let i = 0;
do {
i += 2;
} while (i < 10);
while
while 语句是一种先测试循环语句,先判断再做循环。所以循环体内的代码可能一次都不被执行。
let i = 0;
while (i < 10) {
i += 2;
}
for
for 语句也是先测试语句。
let count = 10;
for (let i = 0; i < count; i++) {
console.log(i);
}
等价于:
let count = 10;
let i = 0;
while (i < count) {
console.log(i);
i++;
}
无法通过 while 循环实现的逻辑,同样也无法使用 for 循环实现。因此 for 循环只是将循环相关的代码封装在了一起而已。
这里建议用 let 声明迭代器变量,具体原因在“变量声明”章节已经说明。
初始化、条件表达式和循环后表达式都不是必需的。因此,下面这种写法可以创建一个无穷循环:
for (;;) {
// 无穷循环
doSomething();
}
如果只包含条件表达式,那么 for 循环实际上就变成了 while 循环:
let count = 10;
let i = 0;
for (; i < count; ) {
console.log(i);
i++;
}
for in
for-in 语句用于枚举对象中的非符号键属性,语法如下:
let window = {
logo: "apple",
system: "macOS"
};
for (const propName in window) {
console.log(propName);
}
// logo
// system
每次循环都会给propName赋予一个window的属性作为值,直到window的所有属性都被枚举一遍。const并不是必需的,但为了确保这个局部变量不会改变,推荐使用const。
注意,对象的属性是无序的。所以for-in并不能保证返回的顺序。
如果用for-in迭代的是null或undefined,则不会执行。
for of
for-of用于遍历可迭代对象的元素
for (const el of [2, 4, 6, 8]) {
document.write(el);
}
for-of迭代了数组中的所有元素。这里的const也并非必需,但是为了确保不变,推荐用const。
for-of会按照可迭代对象的next()方法产生值的顺序迭代元素。
如果尝试迭代的对象不支持迭代,则for-of会抛出错误。比如对上面for-in的对象:
let window = {
logo: "apple",
system: "macOS"
};
for (const el of window) {
document.write(el);
}
// TypeError: window is not iterable
标签语句
标签语句用于给语句加标签(例如下面的start),可以被 break 或 continue 引用。:
start: for (let i = 0; i < count; i++) {
console.log(i);
}
break
break用于直接跳出整个循环过程,并执行循环后面的语句。
let num = 0;
for (let i = 1; i < 10; i++) {
if (i % 5 == 0) {
break;
}
num++;
}
console.log(num); // 4
break和标签语句
let num = 0;
outermost: for (let i = 0; i < 10; i++) {
for (let j = 0; j < 10; j++) {
if (i === 5 && j === 5) {
break outermost;
}
num++;
}
}
console.log(num);
// 55
一般来说break会跳出j的循环,到i的循环。但是因为这里设置了标签,所以会直接连i的循环都跳出。
continue
continue用于仅退出当前循环,并继续循环直到结束。
let num = 0;
for (let i = 1; i < 10; i++) {
if (i % 5 == 0) {
continue;
}
num++;
}
console.log(num); // 8
continue和标签语句
let num = 0;
outermost: for (let i = 0; i < 10; i++) {
for (let j = 0; j < 10; j++) {
if (i === 5 && j === 5) {
continue outermost;
}
num++;
}
}
console.log(num);
// 95
一样的道理,因为会跳到i循环去继续迭代,所以i和j都等于的情况下,j循环内本该执行的5次都被跳过了。所以值只有95。
with
with语句的用途是将代码作用域设置为特定的对象。
这样说很难理解,其实就是对赋值时需要经常用到的一个值操作。
let qs = location.search.substring(1);
let hostName = location.hostname;
let url = location.href;
用with就可以简化为:
with(location) {
let qs = search.substring(1);
let hostName = hostname;
let url = href;
}
严格模式不允许使用with语句。而且with语句影响性能且难以调试,所以不建议大家使用。
switch
switch常用于代替单一且冗长的if语句。
switch (i) {
case 25:
console.log("25");
break;
case 35:
console.log("35");
break;
case 45:
console.log("45");
break;
default:
console.log("Other");
}
为避免不必要的条件判断,最好给每个条件后面都加上 break 语句。如果确实需要连续匹配几个 条件,那么推荐写个注释表明是故意忽略了 break,如下所示:
switch (i) {
case 25:
// 跳过
case 35:
console.log("35");
break;
default:
console.log("Other");
}
ECMAScript的switch语句可用于所有数据类型(在很多语言中,它只能用于数值),因此可以用字符串或对象。条件的值也不需要是常量,可以是变量或表达式:
switch ("hello world") {
case "hello" + " world":
console.log("Greeting was found.");
break;
case "goodbye":
console.log("Closing was found.");
break;
default:
console.log("Unexpected message was found.");
}
// Greeting was found.
第一个条件实际上使用的是表达式,求值为两个字符串拼接后的结果。因为拼接后的结果等于 switch 的参数,所以 console.log 会输出"Greeting was found."。
let num = 25;
switch (true) {
case num < 0:
console.log("Less than 0.");
break;
case num >= 0 && num <= 10:
console.log("Between 0 and 10.");
break;
case num > 10 && num <= 20:
console.log("Between 10 and 20.");
break;
default:
console.log("More than 20.");
}
// More than 20.
因为传入的参数是true,所以会让每个条件的表达式返回布尔值再进行比较。因为没有表达式是true,所以会一直到default。