JavaScript(十六):语句

237 阅读1分钟

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。