附录 1: 更多(晦涩的)控制结构

第二章 中,介绍了一些控制语句,例如 whileforbreak。为了简化,我省略了一些其他控制语句,在我看来,这些控制语句的实用性要低得多。本附录简要描述了这些遗漏的控制语句。


首先是 dodo 的作用与 while 相似,但它不是执行循环体零次或多次,而是执行一次或多次。do 循环的结构如下所示

do {
  var answer = prompt("Say 'moo'.", "");
  print("You said '", answer, "'.");
} while (answer != "moo");

为了强调条件是在循环运行一次 *之后* 才检查的事实,条件语句被写在了循环体的末尾。


接下来是 continue。它与 break 密切相关,并且可以在相同的语句中使用。break 跳出循环,导致程序在循环之后继续执行,而 continue 跳到循环的下一轮迭代。

for (var i = 0; i < 10; i++) {
  if (i % 3 != 0)
    continue;
  print(i, " is divisible by three.");
}

通常可以使用 if 语句来实现类似的效果,但在某些情况下,continue 显得更简洁。


当一个循环嵌套在另一个循环内时,breakcontinue 语句只会影响内部循环。有时你可能需要跳出 *外部* 循环。为了能够引用特定的循环,循环语句可以进行 标记。标记是一个名称(任何有效的变量名都可以),后面跟着一个冒号 (:)。

outer: for (var sideA = 1; sideA < 10; sideA++) {
  inner: for (var sideB = 1; sideB < 10; sideB++) {
    var hypotenuse = Math.sqrt(sideA * sideA + sideB * sideB);
    if (hypotenuse % 1 == 0) {
      print("A right triangle with straight sides of length ",
            sideA, " and ", sideB, " has a hypotenuse of ",
            hypotenuse, ".");
      break outer;
    }
  }
}

接下来,有一个称为 switch 的结构,它可以根据某个值来选择要执行的代码。这是一个非常有用的功能,但 JavaScript 使用的语法(源自 C 语言)过于笨拙和丑陋,所以我通常更喜欢使用 if 语句的链。

function weatherAdvice(weather) {
  switch(weather) {
    case "rainy":
      print("Remember to bring an umbrella.");
      break;
    case "sunny":
      print("Dress lightly.");
    case "cloudy":
      print("Go outside.");
      break;
    default:
      print("Unknown weather type: ", weather);
      break;
  }
}

weatherAdvice("sunny");

switch 打开的代码块中,你可以编写多个 case 标签。程序将跳转到与 switch 收到的值相对应的标签(使用相当于 === 的比较方式,所以没有自动类型转换),或者如果未找到匹配的值,则跳转到 default 标签。然后程序开始执行标签处的语句,并 *继续* 执行其他标签后的语句,直到遇到 break 语句。在某些情况下,例如示例中的 "sunny" case,这可以用于在 case 之间共享部分代码(它建议在晴朗和多云的天气都到户外)。大多数情况下,这只会增加许多丑陋的 break 语句,或者导致你在忘记添加 break 语句时出现问题。

与循环类似,switch 语句也可以被标记。


最后,有一个名为 with 的关键字。我从未在实际程序中 *使用* 过它,但我见过其他人使用它,所以了解它是很有用的。使用 with 的代码如下所示

var scope = "outside";
var object = {name: "Ignatius", scope: "inside"};
with(object) {
  print("Name == ", name, ", scope == ", scope);
  name = "Raoul";
  var newVariable = 49;
}
show(object.name);
show(newVariable);

在代码块内,传递给 with 的对象的属性充当变量。但是,新引入的变量 *不会* 被添加到该对象的属性中。我认为这个结构背后的想法是,它可能在大量使用对象属性的方法中很有用。你可以用 with(this) {...} 来开始这种方法,之后就不必一直写 this 了。