在代码中做出决策——条件语句

在任何编程语言中,代码都需要根据不同的输入做出决策并执行相应的操作。例如,在游戏中,如果玩家的生命值为 0,那么游戏就结束了。在天气应用中,如果在早上查看,则显示日出图像;如果在夜间,则显示星星和月亮。在本文中,我们将探讨 JavaScript 中所谓的条件语句是如何工作的。

预备知识 了解 HTMLCSS 基础,熟悉前面课程中介绍的 JavaScript 基础。
学习成果
  • 了解什么是条件语句——一种根据测试结果运行不同代码路径的代码结构。
  • 使用 if/else/else if 实现条件。
  • 使用比较运算符创建测试。
  • 在测试中实现 AND、OR 和 NOT 逻辑。
  • Switch 语句。
  • 三元运算符。

你可以在一个条件下完成!

人类(和其他动物)一直在做出影响他们生活的决定,从小到大(“我应该吃一块饼干还是两块?”)到大(“我应该留在我的祖国并在家里的农场工作,还是应该搬到美国学习天体物理学?”)

条件语句允许我们在 JavaScript 中表示这种决策过程,从必须做出的选择(例如,“一块饼干还是两块”),到这些选择的最终结果(例如,“吃了一块饼干”的结果可能是“仍然感到饥饿”,“吃了两块饼干”的结果可能是“感到饱了,但妈妈因为我吃光了饼干而责骂我”)。

A cartoon character resembling a person holding a cookie jar labeled 'Cookies'. There is a question mark above the head of the character. There are two speech bubbles. The left speech bubble has one cookie. The right speech bubble has two cookies. Together it implies the character is trying to decide if it wants to one cookie or two cookies.

if...else 语句

让我们来看看 JavaScript 中最常见的条件语句类型——简单的 if...else 语句

基本的 if...else 语法

基本的 if...else 语法如下所示

js
if (condition) {
  /* code to run if condition is true */
} else {
  /* run some other code instead */
}

这里我们有

  1. 关键字 if 后跟一些括号。
  2. 一个要测试的条件,放在括号内(通常是“这个值是否比另一个值大?”或“这个值是否存在?”)。该条件使用我们之前在模块中讨论过的比较运算符,并返回 truefalse
  3. 一对花括号,其中包含一些代码——这可以是任何我们喜欢的代码,并且只有在条件返回 true 时才会运行。
  4. 关键字 else
  5. 另一对花括号,其中包含更多代码——这可以是任何我们喜欢的代码,并且只有在条件不为 true 时才会运行——换句话说,条件为 false

这段代码非常易读——它表示“如果 条件 返回 true,则运行代码 A,否则 运行代码 B”。

你应该注意,你不必包含 else 和第二个花括号块——以下也是完全合法的代码

js
if (condition) {
  /* code to run if condition is true */
}

/* run some other code */

但是,在这里你需要小心——在这种情况下,第二个代码块不受条件语句控制,所以它总是运行,无论条件返回 true 还是 false。这不一定是坏事,但这可能不是你想要的——通常你希望运行一个代码块另一个,而不是两者都运行。

最后一点,虽然不推荐,但你有时可能会看到没有花括号的 if...else 语句

js
if (condition) doSomething();
else doSomethingElse();

这种语法是完全有效的,但是如果你使用花括号来界定代码块,并使用多行和缩进,代码会更容易理解。

一个真实示例

为了更好地理解这种语法,让我们考虑一个真实的例子。想象一个孩子被他们的母亲或父亲要求帮忙做家务。父母可能会说:“嘿,甜心!如果你帮我购物,我会给你一些额外的零用钱,这样你就能买得起你想要的玩具了。”在 JavaScript 中,我们可以这样表示:

js
let shoppingDone = false;
let childAllowance;

if (shoppingDone === true) {
  childAllowance = 10;
} else {
  childAllowance = 5;
}

如所示,这段代码总是导致 shoppingDone 变量返回 false,这意味着我们可怜的孩子会失望。这将由我们来提供一种机制,让父母在孩子购物后将 shoppingDone 变量设置为 true

注意: 你可以在 GitHub 上查看此示例的更完整版本(也可以查看其实时运行)。

else if

上一个示例为我们提供了两种选择或结果——但是如果我们想要两种以上呢?

有一种方法可以将额外的选择/结果链接到你的 if...else——使用 else if。每个额外的选择都需要一个额外的块放在 if () { }else { } 之间——请看下面的更复杂的示例,它可能是一个简单的天气预报应用程序的一部分:

html
<label for="weather">Select the weather type today: </label>
<select id="weather">
  <option value="">--Make a choice--</option>
  <option value="sunny">Sunny</option>
  <option value="rainy">Rainy</option>
  <option value="snowing">Snowing</option>
  <option value="overcast">Overcast</option>
</select>

<p></p>
js
const select = document.querySelector("select");
const para = document.querySelector("p");

select.addEventListener("change", setWeather);

function setWeather() {
  const choice = select.value;

  if (choice === "sunny") {
    para.textContent =
      "It is nice and sunny outside today. Wear shorts! Go to the beach, or the park, and get an ice cream.";
  } else if (choice === "rainy") {
    para.textContent =
      "Rain is falling outside; take a rain coat and an umbrella, and don't stay out for too long.";
  } else if (choice === "snowing") {
    para.textContent =
      "The snow is coming down — it is freezing! Best to stay in with a cup of hot chocolate, or go build a snowman.";
  } else if (choice === "overcast") {
    para.textContent =
      "It isn't raining, but the sky is grey and gloomy; it could turn any minute, so take a rain coat just in case.";
  } else {
    para.textContent = "";
  }
}
  1. 这里我们有一个 HTML <select> 元素,允许我们做出不同的天气选择,以及一个简单的段落。
  2. 在 JavaScript 中,我们存储了对 <select><p> 元素的引用,并向 <select> 元素添加了一个事件监听器,以便当其值更改时,setWeather() 函数会运行。
  3. 当此函数运行时,我们首先将一个名为 choice 的变量设置为 <select> 元素中当前选定的值。然后,我们使用条件语句根据 choice 的值在段落中显示不同的文本。请注意,除了第一个条件在 if () { } 块中测试之外,所有条件都在 else if () { } 块中进行测试。
  4. else { } 块中的最后一个选择基本上是一个“最后手段”选项——如果所有条件都不为 true,其中的代码将运行。在这种情况下,它用于清空段落中的文本,例如,如果用户决定重新选择开头显示的“--Make a choice--”占位符选项。

注意: 你也可以在 GitHub 上找到此示例(也可在此处查看其实时运行)。

关于比较运算符的说明

比较运算符用于测试条件语句中的条件。我们首先在 JavaScript 中的基本数学——数字和运算符一文中回顾了比较运算符。我们的选择有:

  • ===!== — 测试一个值是否与另一个值相同,或不相同。
  • <> — 测试一个值是否小于或大于另一个值。
  • <=>= — 测试一个值是否小于或等于,或大于或等于另一个值。

我们特别提到了布尔值(true/false)的测试,以及你将反复遇到的一种常见模式。任何不是 falseundefinednull0NaN 或空字符串('')的值,在作为条件语句测试时实际上都返回 true,因此你可以单独使用变量名来测试它是否为 true,甚至测试它是否存在(即它不是未定义的)。例如:

js
let cheese = "Cheddar";

if (cheese) {
  console.log("Yay! Cheese available for making cheese on toast.");
} else {
  console.log("No cheese on toast for you today.");
}

回到我们之前关于孩子为父母做家务的例子,你可以这样写

js
let shoppingDone = false;
let childAllowance;

// We don't need to explicitly specify 'shoppingDone === true'
if (shoppingDone) {
  childAllowance = 10;
} else {
  childAllowance = 5;
}

嵌套 if...else

将一个 if...else 语句嵌套在另一个语句中是完全可以的——即嵌套它们。例如,我们可以更新我们的天气预报应用程序,根据温度显示一组更进一步的选择:

js
if (choice === "sunny") {
  if (temperature < 86) {
    para.textContent = `It is ${temperature} degrees outside — nice and sunny. Let's go out to the beach, or the park, and get an ice cream.`;
  } else if (temperature >= 86) {
    para.textContent = `It is ${temperature} degrees outside — REALLY HOT! If you want to go outside, make sure to put some sunscreen on.`;
  }
}

尽管所有代码协同工作,但每个 if...else 语句都完全独立于另一个语句。

逻辑运算符:AND、OR 和 NOT

如果你想测试多个条件而不想编写嵌套的 if...else 语句,逻辑运算符可以帮助你。当在条件中使用时,前两个运算符的作用如下:

  • && — AND;允许你将两个或更多表达式链接在一起,以便所有表达式都必须单独评估为 true,整个表达式才返回 true
  • || — OR;允许你将两个或更多表达式链接在一起,以便其中一个或多个表达式必须单独评估为 true,整个表达式才返回 true

举个 AND 的例子,前面的代码片段可以改写成这样

js
if (choice === "sunny" && temperature < 86) {
  para.textContent = `It is ${temperature} degrees outside — nice and sunny. Let's go out to the beach, or the park, and get an ice cream.`;
} else if (choice === "sunny" && temperature >= 86) {
  para.textContent = `It is ${temperature} degrees outside — REALLY HOT! If you want to go outside, make sure to put some sunscreen on.`;
}

所以,例如,第一个代码块只会在 choice === 'sunny' 并且 temperature < 86 都返回 true 时运行。

我们来看一个快速的 OR 示例

js
if (iceCreamVanOutside || houseStatus === "on fire") {
  console.log("You should leave the house quickly.");
} else {
  console.log("Probably should just stay in then.");
}

最后一种逻辑运算符是 NOT,用 ! 运算符表示,可以用于否定一个表达式。让我们在上例中将其与 OR 结合使用

js
if (!(iceCreamVanOutside || houseStatus === "on fire")) {
  console.log("Probably should just stay in then.");
} else {
  console.log("You should leave the house quickly.");
}

在这段代码中,如果 OR 语句返回 true,NOT 运算符将否定它,使得整个表达式返回 false

你可以根据需要组合任意数量的逻辑语句,无论采用何种结构。以下示例仅当两个 OR 语句都返回 true 时才执行内部代码,这意味着整个 AND 语句将返回 true

js
if ((x === 5 || y > 3 || z <= 10) && (loggedIn || userName === "Steve")) {
  // run the code
}

在条件语句中使用逻辑或运算符时,一个常见的错误是尝试只声明一次要检查其值的变量,然后给出它可能返回 true 的值列表,并用 || (OR) 运算符分隔。例如:

js
if (x === 5 || 7 || 10 || 20) {
  // run my code
}

在这种情况下,if () 内的条件将始终评估为 true,因为 7(或任何其他非零值)始终评估为 true。这个条件实际上是说“如果 x 等于 5,或者 7 是 true——它总是 true”。这在逻辑上不是我们想要的!要使其正常工作,你必须在每个 OR 运算符的两侧指定一个完整的测试

js
if (x === 5 || x === 7 || x === 10 || x === 20) {
  // run my code
}

switch 语句

if...else 语句能够很好地实现条件代码,但它们并非没有缺点。它们主要适用于只有几个选择,每个选择都需要运行相当多的代码,并且/或者条件很复杂(例如,有多个逻辑运算符)的情况。对于你只想根据条件将变量设置为某个选择的值或打印出特定语句的情况,语法可能有点笨重,特别是当你有大量选择时。

在这种情况下,switch 语句就是你的朋友——它们将单个表达式/值作为输入,然后遍历几个选择,直到找到与该值匹配的选择,并执行与之相关的相应代码。这里有一些伪代码,给你一个概念:

js
switch (expression) {
  case choice1:
    // run this code
    break;

  case choice2:
    // run this code instead
    break;

  // include as many cases as you like

  default:
    // actually, just run this code
    break;
}

这里我们有

  1. 关键字 switch,后跟一组括号。
  2. 括号内的表达式或值。
  3. 关键字 case,后跟表达式/值可能成为的选择,再后跟一个冒号。
  4. 如果选择与表达式匹配,则运行一些代码。
  5. 一个 break 语句,后跟一个分号。如果前一个选择与表达式/值匹配,浏览器将在此处停止执行代码块,并继续执行 switch 语句下方出现的任何代码。
  6. 尽可能多的其他情况(第 3-5 点)。
  7. 关键字 default,后面跟着与其中一个 case(第 3-5 点)完全相同的代码模式,只是 default 后面没有选择,而且你不需要 break 语句,因为在这个块之后无论如何都没有要运行的代码。这是在没有任何选择匹配时的默认选项。

注意: 你不必包含 default 部分——如果表达式不可能最终等于未知值,你可以安全地省略它。但是,如果存在这种可能性,你需要包含它来处理未知情况。

一个 switch 示例

让我们看一个真实的例子——我们将重写我们的天气预报应用程序,转而使用 switch 语句

html
<label for="weather">Select the weather type today: </label>
<select id="weather">
  <option value="">--Make a choice--</option>
  <option value="sunny">Sunny</option>
  <option value="rainy">Rainy</option>
  <option value="snowing">Snowing</option>
  <option value="overcast">Overcast</option>
</select>

<p></p>
js
const select = document.querySelector("select");
const para = document.querySelector("p");

select.addEventListener("change", setWeather);

function setWeather() {
  const choice = select.value;

  switch (choice) {
    case "sunny":
      para.textContent =
        "It is nice and sunny outside today. Wear shorts! Go to the beach, or the park, and get an ice cream.";
      break;
    case "rainy":
      para.textContent =
        "Rain is falling outside; take a rain coat and an umbrella, and don't stay out for too long.";
      break;
    case "snowing":
      para.textContent =
        "The snow is coming down — it is freezing! Best to stay in with a cup of hot chocolate, or go build a snowman.";
      break;
    case "overcast":
      para.textContent =
        "It isn't raining, but the sky is grey and gloomy; it could turn any minute, so take a rain coat just in case.";
      break;
    default:
      para.textContent = "";
  }
}

注意: 你也可以在 GitHub 上找到此示例(在此处查看其实时运行)。

三元运算符

在我们让你练习一些示例之前,我们想向你介绍最后一个语法。 三元运算符或条件运算符是一种测试条件并返回一个值/表达式(如果为 true)或另一个值/表达式(如果为 false)的小段语法——这在某些情况下可能很有用,并且如果通过 true/false 条件在两个选择之间进行选择,它比 if...else 块占用的代码要少得多。伪代码如下所示

js
condition ? run this code : run this code instead

我们来看一个例子

js
const greeting = isBirthday
  ? "Happy birthday Mrs. Smith — we hope you have a great day!"
  : "Good morning Mrs. Smith.";

这里我们有一个名为 isBirthday 的变量——如果它为 true,我们向客人发送生日快乐的消息;如果不是,我们给她标准的日常问候。

三元运算符示例

三元运算符不仅用于设置变量值;你还可以运行函数或代码行——任何你喜欢的。以下实时示例展示了一个简单的主题选择器,其中使用三元运算符应用网站的样式。

html
<label for="theme">Select theme: </label>
<select id="theme">
  <option value="white">White</option>
  <option value="black">Black</option>
</select>

<h1>This is my website</h1>
js
const select = document.querySelector("select");
const html = document.querySelector("html");
document.body.style.padding = "10px";

function update(bgColor, textColor) {
  html.style.backgroundColor = bgColor;
  html.style.color = textColor;
}

select.addEventListener("change", () =>
  select.value === "black"
    ? update("black", "white")
    : update("white", "black"),
);

这里我们有一个 <select> 元素用于选择主题(黑色或白色),以及一个简单的 h1 用于显示网站标题。我们还有一个名为 update() 的函数,它接受两种颜色作为参数(输入)。网站的背景颜色设置为提供的第一种颜色,文本颜色设置为提供的第二种颜色。

最后,我们还有一个 onchange 事件监听器,用于运行一个包含三元运算符的函数。它以一个测试条件开始——select.value === 'black'。如果它返回 true,我们使用黑色和白色参数运行 update() 函数,这意味着我们最终得到黑色的背景颜色和白色的文本颜色。如果它返回 false,我们使用白色和黑色参数运行 update() 函数,这意味着网站颜色会反转。

注意: 你也可以在 GitHub 上找到此示例(在此处查看其实时运行)。

实现一个基本日历

在这个例子中,你将帮助我们完成一个基本的日历应用程序。在你的代码中,你将拥有

  • 一个 <select> 元素,允许用户在不同的月份之间进行选择。
  • 一个 change 事件处理程序,用于检测 <select> 菜单中选定的值何时更改。
  • 一个名为 createCalendar() 的函数,它绘制日历并在 h1 元素中显示正确的月份。

完成示例

  1. 单击下面代码块中的**“播放”**以在 MDN Playground 中编辑示例。
  2. createCalendar() 函数中,紧跟在 // ADD CONDITIONAL HERE 注释下方编写一个条件语句。它应该
    1. 查看选定的月份(存储在 choice 变量中。这将是值更改后 <select> 元素的值,例如“January”)。
    2. days 变量赋值为所选月份的天数。为此,你需要查阅一年中每个月份的天数。在此示例中,你可以忽略闰年。

提示

  • 建议您使用逻辑 OR 将多个月份分组为一个条件;它们中的许多月份天数相同。
  • 思考哪个月的天数最常见,并将其作为默认值。

如果你犯了错误,可以使用 MDN Playground 中的 _重置_ 按钮清除你的工作。如果你实在卡住了,可以在实时输出下方查看解决方案。

js
const select = document.querySelector("select");
const list = document.querySelector("ul");
const h1 = document.querySelector("h1");

select.addEventListener("change", () => {
  const choice = select.value;
  createCalendar(choice);
});

function createCalendar(month) {
  let days = 31;

  // ADD CONDITIONAL HERE

  list.textContent = "";
  h1.textContent = month;
  for (let i = 1; i <= days; i++) {
    const listItem = document.createElement("li");
    listItem.textContent = i;
    list.appendChild(listItem);
  }
}

select.value = "January";
createCalendar("January");
点击此处显示解决方案

你完成的 JavaScript 应该如下所示

js
const select = document.querySelector("select");
const list = document.querySelector("ul");
const h1 = document.querySelector("h1");

select.addEventListener("change", () => {
  const choice = select.value;
  createCalendar(choice);
});

function createCalendar(month) {
  let days = 31;

  if (month === "February") {
    days = 28;
  } else if (
    month === "April" ||
    month === "June" ||
    month === "September" ||
    month === "November"
  ) {
    days = 30;
  }

  list.textContent = "";
  h1.textContent = month;
  for (let i = 1; i <= days; i++) {
    const listItem = document.createElement("li");
    listItem.textContent = i;
    list.appendChild(listItem);
  }
}

select.value = "January";
createCalendar("January");

添加更多颜色选择

在此示例中,你将使用我们前面看到的三元运算符示例,并将三元运算符转换为 switch 语句,以允许我们为网站应用更多选择。查看 <select> — 这次你会看到它不是只有两个主题选项,而是五个。

完成示例

  1. 单击下面代码块中的**“播放”**以在 MDN Playground 中编辑示例。
  2. // ADD SWITCH STATEMENT 注释下方添加一个 switch 语句
    1. 它应该接受 choice 变量作为其输入表达式。
    2. 对于每个 case,选择应等于可选的 <option> 值之一,即 whiteblackpurpleyellowpsychedelic。请注意,选项值是小写的,而选项标签(如实时输出中所示)是首字母大写的。您应该在代码中使用小写值。
    3. 对于每种情况,都应运行 update() 函数,并传入两个颜色值,第一个用于背景颜色,第二个用于文本颜色。请记住,颜色值是字符串,因此需要用引号括起来。

如果你犯了错误,可以使用 MDN Playground 中的 _重置_ 按钮清除你的工作。如果你实在卡住了,可以在实时输出下方查看解决方案。

js
const select = document.querySelector("select");
const html = document.querySelector("html");

select.addEventListener("change", () => {
  const choice = select.value;

  // ADD SWITCH STATEMENT
});

function update(bgColor, textColor) {
  html.style.backgroundColor = bgColor;
  html.style.color = textColor;
}
点击此处显示解决方案

你完成的 JavaScript 应该如下所示

js
const select = document.querySelector("select");
const html = document.querySelector("html");

select.addEventListener("change", () => {
  const choice = select.value;

  switch (choice) {
    case "black":
      update("black", "white");
      break;
    case "white":
      update("white", "black");
      break;
    case "purple":
      update("purple", "white");
      break;
    case "yellow":
      update("yellow", "purple");
      break;
    case "psychedelic":
      update("lime", "purple");
      break;
  }
});

function update(bgColor, textColor) {
  html.style.backgroundColor = bgColor;
  html.style.color = textColor;
}

总结

目前,关于 JavaScript 中的条件结构,你真正需要知道的就是这些了!在下一篇文章中,我们将为你提供一些测试,你可以用它们来检查你对这些信息的理解和记忆程度。

另见