Skip to content

条件分支

有时我们需要根据不同条件执行不同的操作。

我们可以使用 if 语句和条件运算符 ?(也称为“问号”运算符)来实现。

"if" 语句

if(...) 语句计算括号里的条件表达式,如果计算结果是 true,就会执行对应的代码块。

例如:

js
let year = prompt('In which year was ECMAScript-2015 specification published?', '');

if (year == 2015) alert( 'You are right!' );

在上面这个例子中,条件是一个简单的相等性检查(year == 2015),但它还可以更复杂。

如果有多个语句要执行,我们必须将要执行的代码块封装在大括号内:

js
if (year == 2015) {
  alert( "That's correct!" );
  alert( "You're so smart!" );
}

即使只有一条语句,但也建议每次使用 if 语句时都用大括号 {} 来包装代码块。这样可以提高代码可读性。

布尔转换

if(...) 语句会计算圆括号内的表达式,并将计算结果转换为布尔型。

类型转换(布尔型转换) 中,提到:

  • 数字 0、空字符串 ""nullundefinedNaN 都会被转换成 false。因为它们被称为“假值(falsy)”。
  • 其他值被转换为 true,所以它们被称为“真值(truthy)”。

所以,下面这个条件下的代码永远不会执行:

js
if (0) { // 0 是假值(falsy)
  ...
}

但下面的条件 —— 始终有效:

js
if (1) { // 1 是真值(truthy)
  ...
}

我们也可以将预先计算的布尔值传入 if 语句,像这样:

js
let cond = (year == 2015); // 相等运算符的结果是 true 或 false

if (cond) {
  ...
}

"else" 语句

if 语句有时会包含一个可选的 “else” 块。如果判断条件不成立,就会执行它内部的代码。

例如:

js
let year = prompt('In which year was ECMAScript-2015 specification published?', '');

if (year == 2015) {
  alert( 'You guessed it right!' );
} else {
  alert( 'How can you be so wrong?' ); // 2015 以外的任何值
}

多个条件:"else if"

有时我们需要测试一个条件的几个变体。我们可以通过使用 else if 子句实现。

例如:

js
let year = prompt('In which year was ECMAScript-2015 specification published?', '');

if (year < 2015) {
  alert( 'Too early...' );
} else if (year > 2015) {
  alert( 'Too late' );
} else {
  alert( 'Exactly!' );
}

在上面的代码中,JavaScript 先检查 year < 2015。如果条件不符合,就会转到下一个条件 year > 2015。如果这个条件也不符合,则会显示最后一个 alert

可以有更多的 else if 块。结尾的 else 是可选的。

条件运算符 ?

有时我们需要根据一个条件去赋值一个变量。

如下所示:

js
let accessAllowed;
let age = prompt('How old are you?', '');

if (age > 18) {
  accessAllowed = true;
} else {
  accessAllowed = false;
}

alert(accessAllowed);

所谓的“条件”或“问号”运算符让我们可以更简短地达到目的。

这个运算符通过问号 ? 表示。有时它被称为三元运算符,被称为“三元”是因为该运算符中有三个操作数。实际上它是 JavaScript 中唯一一个有这么多操作数的运算符。

语法:

js
let result = condition ? value1 : value2;

计算条件结果,如果结果为真,则返回 value1,否则返回 value2

例如:

js
let accessAllowed = (age > 18) ? true : false;

技术上讲,我们可以省略 age > 18 外面的括号。问号运算符的优先级较低,所以它会在比较运算符 > 后执行。

下面这个示例会执行和前面那个示例相同的操作:

js
// 比较运算符 "age > 18" 首先执行
//(不需要将其包含在括号中)
let accessAllowed = age > 18 ? true : false;

但括号可以使代码可读性更强,所以我们建议使用它们。

你也可以不使用问号运算符,因为比较本身就返回 true/false:

js
// 下面代码同样可以实现
let accessAllowed = age > 18;

多个 ?

使用一系列问号 ? 运算符可以返回一个取决于多个条件的值。

例如:

js
let age = prompt('age?', 18);

let message = (age < 3) ? 'Hi, baby!' :
              (age < 18) ? 'Hello!' :
              (age < 100) ? 'Greetings!' :
              'What an unusual age!';

alert( message );

可能很难一下子看出发生了什么。但经过仔细观察,我们可以看到它只是一个普通的检查序列。

  1. 第一个问号检查 age < 3
  2. 如果为真 — 返回 'Hi, baby!'。否则,会继续执行冒号 ":" 后的表达式,检查 age < 18
  3. 如果为真 — 返回 'Hello!'。否则,会继续执行下一个冒号 ":" 后的表达式,检查 age < 100
  4. 如果为真 — 返回 'Greetings!'。否则,会继续执行最后一个冒号 ":" 后面的表达式,返回 'What an unusual age!'

这是使用 if..else 实现上面的逻辑的写法:

js
if (age < 3) {
  message = 'Hi, baby!';
} else if (age < 18) {
  message = 'Hello!';
} else if (age < 100) {s
  message = 'Greetings!';
} else {
  message = 'What an unusual age!';
}

? 的非常规使用

有时可以使用问号 ? 来代替 if 语句:

js
let company = prompt('Which company created JavaScript?', '');

(company == 'Netscape') ?
   alert('Right!') : alert('Wrong.');

根据条件 company =='Netscape',要么执行 ? 后面的第一个表达式并显示对应内容,要么执行第二个表达式并显示对应内容。

在这里我们不是把结果赋值给变量。而是根据条件执行不同的代码。

不建议这样使用问号运算符。

这种写法比 if 语句更短。但它的可读性差。

下面是使用 if 语句实现相同功能的代码,进行下比较:

js
let company = prompt('Which company created JavaScript?', '');

if (company == 'Netscape') {
  alert('Right!');
} else {
  alert('Wrong.');
}

因为我们的眼睛垂直扫描代码。所以,跨越几行的代码块比长而水平的代码更易于理解。

问号 ? 的作用是根据条件返回其中一个值。请正确使用它。当需要执行不同的代码分支时,请使用 if。

"switch" 语句

switch 语句可以替代多个 if 判断。

switch 语句为多分支选择的情况提供了一个更具描述性的方式。

语法

switch 语句有至少一个 case 代码块和一个 可选的 default 代码块。

就像这样:

js
switch(x) {
  case 'value1':  // if (x === 'value1')
    ...
    [break]

  case 'value2':  // if (x === 'value2')
    ...
    [break]

  default:
    ...
    [break]
}
  • 比较 x 值与第一个 case(也就是 value1)是否严格相等,然后比较第二个 casevalue2)以此类推。
  • 如果相等,switch 语句就执行相应 case 下的代码块,直到遇到最靠近的 break 语句(或者直到 switch 语句末尾)。
  • 如果没有符合的 case,则执行 default 代码块(如果 default 存在)。

举个例子

switch 的例子(高亮的部分是执行的 case 部分):

js
let a = 2 + 2;

switch (a) {
  case 3:
    alert( 'Too small' );
    break;
  case 4:
    alert( 'Exactly!' );
    break;
  case 5:
    alert( 'Too big' );
    break;
  default:
    alert( "I don't know such values" );
}

这里的 switch 从第一个 case 分支开始将 a 的值与 case 后的值进行比较,第一个 case 后的值为 3 匹配失败。

然后比较 4。匹配,所以从 case 4 开始执行直到遇到最近的 break。

如果没有 break,程序将不经过任何检查就会继续执行下一个 case。

无 break 的例子:

js
let a = 2 + 2;

switch (a) {
  case 3:
    alert( 'Too small' );
  case 4:
    alert( 'Exactly!' );
  case 5:
    alert( 'Too big' );
  default:
    alert( "I don't know such values" );
}

在上面的例子中我们会看到连续执行的三个 alert:

  1. alert( 'Exactly!' );
  2. alert( 'Too big' );
  3. alert( "I don't know such values" );

任何表达式都可以成为 switch/case 的参数

switchcase 都允许任意表达式。

比如:

js
let a = "1";
let b = 0;

switch (+a) {
  case b + 1:
    alert("this runs, because +a is 1, exactly equals b+1");
    break;

  default:
    alert("this doesn't run");
}

这里 +a 返回 1,这个值跟 caseb + 1 相比较,然后执行对应的代码。

"case" 分组

共享同一段代码的几个 case 分支可以被分为一组:

比如,如果我们想让 case 3case 5 执行同样的代码:

js
let a = 3;

switch (a) {
  case 4:
    alert('Right!');
    break;

  case 3: // (*) 下面这两个 case 被分在一组
  case 5:
    alert('Wrong!');
    alert("Why don't you take a math class?");
    break;

  default:
    alert('The result is strange. Really.');
}

现在 35 都显示相同的信息。

switch/case 有通过 case 进行“分组”的能力,其实是 switch 语句没有 break 时的副作用。因为没有 breakcase 3 会从 (*) 行执行到 case 5

类型很关键

强调一下,这里的相等是 严格相等。被比较的值必须是相同的类型才能进行匹配。

比如,我们来看下面的代码:

js
let arg = prompt("Enter a value?");

switch (arg) {
  case '0':
  case '1':
    alert( 'One or zero' );
    break;

  case '2':
    alert( 'Two' );
    break;

  case 3:
    alert( 'Never executes!' );
    break;
  default:
    alert( 'An unknown value' );
}
  1. 在 prompt 对话框输入 01,第一个 alert 弹出。
  2. 输入 2,第二个 alert 弹出。
  3. 但是输入 3,因为 prompt 的结果是字符串类型的 "3",不严格相等 === 于数字类型的 3,所以 case 3 不会执行!因此 case 3 部分是一段无效代码。所以会执行 default 分支。

基于 MIT 许可发布