if语句 、 三元运算符‘?‘、循环、switch语句

if 语句

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

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

布尔转换

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

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

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

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

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

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

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

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

if (cond) {
  ...
}

if else 语句

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

例如:

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 子句实现。

例如:

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 是可选的。

三元运算符 ?

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

如下所示:

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

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

alert(accessAllowed);

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

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

语法:

let result = condition ? value1 : value2;

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

例如:

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

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

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

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

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

请注意:

在上面的例子中,你可以不使用问号运算符,因为比较本身就返回 true/false

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

多个 ?

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

例如:

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 实现上面的逻辑的写法:

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

? 的非常规使用

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

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

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

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

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

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

这种写法比 if 语句更短,对一些程序员很有吸引力。但它的可读性差。

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

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

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

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

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

循环:while、do while、for

我们经常需要重复执行一些操作。

例如,我们需要将列表中的商品逐个输出,或者运行相同的代码将数字 1 到 10 逐个输出。

循环 是一种重复运行同一代码的方法。

while 循环

while 循环的语法如下:

while (condition) {
  // 代码
  // 所谓的“循环体”
}

condition 为真时,执行循环体的 code

例如,以下将循环输出当 i < 3 时的 i 值:

let i = 0;
while (i < 3) { // 依次显示 0、1 和 2
  alert( i );
  i++;
}

循环体的单次执行叫作 一次迭代。上面示例中的循环进行了三次迭代。

如果上述示例中没有 i++,那么循环(理论上)会永远重复执行下去。实际上,浏览器提供了阻止这种循环的方法,我们可以通过终止进程,来停掉服务器端的 JavaScript。

任何表达式或变量都可以是循环条件,而不仅仅是比较。在 while 中的循环条件会被计算,计算结果会被转化为布尔值。

例如,while (i != 0) 可简写为 while (i)

let i = 3;
while (i) { // 当 i 变成 0 时,条件为假,循环终止
  alert( i );
  i--;
}

单行循环体不需要大括号

如果循环体只有一条语句,则可以省略大括号 {…}

let i = 3;
while (i) alert(i--);

do…while 循环

使用 do..while 语法可以将条件检查移至循环体 下面

do {
  // 循环体
} while (condition);

循环首先执行循环体,然后检查条件,当条件为真时,重复执行循环体。

例如:

let i = 0;
do {
  alert( i );
  i++;
} while (i < 3);

这种形式的语法很少使用,除非你希望不管条件是否为真,循环体 至少执行一次。通常我们更倾向于使用另一个形式:while(…) {…}

for循环

for 循环更加复杂,但它是最常使用的循环形式。

for 循环看起来就像这样:

for (begin; condition; step) {
  // ……循环体……
}

我们通过示例来了解一下这三个部分的含义。下述循环从 i 等于 03(但不包括 3)运行 alert(i)

for (let i = 0; i < 3; i++) { // 结果为 0、1、2
  alert(i);
}

我们逐个部分分析 for 循环:

语句段
begini = 0进入循环时执行一次。
conditioni < 3在每次循环迭代之前检查,如果为 false,停止循环。
body(循环体)alert(i)条件为真时,重复运行。
stepi++在每次循环体迭代后执行。

一般循环算法的工作原理如下:

开始运行
→ (如果 condition 成立 → 运行 body 然后运行 step)
→ (如果 condition 成立 → 运行 body 然后运行 step)
→ (如果 condition 成立 → 运行 body 然后运行 step)
→ ...

所以,begin 执行一次,然后进行迭代:每次检查 condition 后,执行 bodystep

如果你这是第一次接触循环,那么回到这个例子,在一张纸上重现它逐步运行的过程,可能会对你有所帮助。

以下是在这个示例中发生的事:

// for (let i = 0; i < 3; i++) alert(i)

// 开始
let i = 0
// 如果条件为真,运行下一步
if (i < 3) { alert(i); i++ }
// 如果条件为真,运行下一步
if (i < 3) { alert(i); i++ }
// 如果条件为真,运行下一步
if (i < 3) { alert(i); i++ }
// ……结束,因为现在 i == 3

内联变量声明

这里“计数”变量 i 是在循环中声明的。这叫做“内联”变量声明。这样的变量只在循环中可见。

for (let i = 0; i < 3; i++) {
  alert(i); // 0, 1, 2
}
alert(i); // 错误,没有这个变量。

除了定义一个变量,我们也可以使用现有的变量:

let i = 0;

for (i = 0; i < 3; i++) { // 使用现有的变量
  alert(i); // 0, 1, 2
}

alert(i); //3,可见,因为是在循环之外声明的

省略语句段

for 循环的任何语句段都可以被省略。

例如,如果我们在循环开始时不需要做任何事,我们就可以省略 begin 语句段。

就像这样:

let i = 0; // 我们已经声明了 i 并对它进行了赋值

for (; i < 3; i++) { // 不再需要 "begin" 语句段
  alert( i ); // 0, 1, 2
}

我们也可以移除 step 语句段:

let i = 0;

for (; i < 3;) {
  alert( i++ );
}

该循环与 while (i < 3) 等价。

实际上我们可以删除所有内容,从而创建一个无限循环:

for (;;) {
  // 无限循环
}

请注意 for 的两个 ; 必须存在,否则会出现语法错误。

跳出循环

通常条件为假时,循环会终止。

但我们随时都可以使用 break 指令强制退出。

例如,下面这个循环要求用户输入一系列数字,在输入的内容不是数字时“终止”循环。

let sum = 0;

while (true) {

  let value = +prompt("Enter a number", '');

  if (!value) break; // (*)

  sum += value;

}
alert( 'Sum: ' + sum );

如果用户输入空行或取消输入,在 (*) 行的 break 指令会被激活。它立刻终止循环,将控制权传递给循环后的第一行,即,alert

根据需要,"无限循环 + break" 的组合非常适用于不必在循环开始/结束时检查条件,但需要在中间甚至是主体的多个位置进行条件检查的情况。

继续下一次迭代

continue 指令是 break 的“轻量版”。它不会停掉整个循环。而是停止当前这一次迭代,并强制启动新一轮循环(如果条件允许的话)。

如果我们完成了当前的迭代,并且希望继续执行下一次迭代,我们就可以使用它。

下面这个循环使用 continue 来只输出奇数:

for (let i = 0; i < 10; i++) {

  //如果为真,跳过循环体的剩余部分。
  if (i % 2 == 0) continue;

  alert(i); // 1,然后 3,5,7,9
}

对于偶数的 i 值,continue 指令会停止本次循环的继续执行,将控制权传递给下一次 for 循环的迭代(使用下一个数字)。因此 alert 仅被奇数值调用。

continue 指令利于减少嵌套

显示奇数的循环可以像下面这样:

for (let i = 0; i < 10; i++) {

  if (i % 2) {
    alert( i );
  }

}

从技术角度看,它与上一个示例完全相同。当然,我们可以将代码包装在 if 块而不使用 continue

但在副作用方面,它多创建了一层嵌套(大括号内的 alert 调用)。如果 if 中代码有多行,则可能会降低代码整体的可读性。

禁止 break/continue 在 ‘?’ 的右边

请注意非表达式的语法结构不能与三元运算符 ? 一起使用。特别是 break/continue 这样的指令是不允许这样使用的。

例如,我们使用如下代码:

if (i > 5) {
  alert(i);
} else {
  continue;
}

……用问号重写:

(i > 5) ? alert(i) : continue; // continue 不允许在这个位置

……代码会停止运行,并显示有语法错误。

这是不(建议)使用问号 ? 运算符替代 if 语句的另一个原因。

break/continue 标签

有时候我们需要从一次从多层嵌套的循环中跳出来。

例如,下述代码中我们的循环使用了 ij,从 (0,0)(3,3) 提示坐标 (i, j)

for (let i = 0; i < 3; i++) {

  for (let j = 0; j < 3; j++) {

    let input = prompt(`Value at coords (${i},${j})`, '');

    // 如果我想从这里退出并直接执行 alert('Done!')
  }
}

alert('Done!');

我们需要提供一种方法,以在用户取消输入时来停止这个过程。

input 之后的普通 break 只会打破内部循环。这还不够 —— 标签可以实现这一功能!

标签 是在循环之前带有冒号的标识符:

labelName: for (...) {
  ...
}

break <labelName> 语句跳出循环至标签处:

outer: for (let i = 0; i < 3; i++) {

  for (let j = 0; j < 3; j++) {

    let input = prompt(`Value at coords (${i},${j})`, '');

    // 如果是空字符串或被取消,则中断并跳出这两个循环。
    if (!input) break outer; // (*)

    // 用得到的值做些事……
  }
}
alert('Done!');

上述代码中,break outer 向上寻找名为 outer 的标签并跳出当前循环。

因此,控制权直接从 (*) 转至 alert('Done!')

我们还可以将标签移至单独一行:

outer:
for (let i = 0; i < 3; i++) { ... }

continue 指令也可以与标签一起使用。在这种情况下,执行跳转到标记循环的下一次迭代。

标签并不允许“跳到”所有位置

标签不允许我们跳到代码的任意位置。

例如,这样做是不可能的:

break label;  // 无法跳转到这个标签

label: for (...)

只有在循环内部才能调用 break/continue,并且标签必须位于指令上方的某个位置。

总结

我们学习了三种循环:

  • while —— 每次迭代之前都要检查条件。
  • do..while —— 每次迭代后都要检查条件。
  • for (;;) —— 每次迭代之前都要检查条件,可以使用其他设置。

通常使用 while(true) 来构造“无限”循环。这样的循环和其他循环一样,都可以通过 break 指令来终止。

如果我们不想在当前迭代中做任何事,并且想要转移至下一次迭代,那么可以使用 continue 指令。

break/continue 支持循环前的标签。标签是 break/continue 跳出嵌套循环以转到外部的唯一方法。

switch 语句

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

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

语法

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

就像这样:

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 部分):

let a = 2 + 2;

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

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

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

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

break 的例子:

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

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

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

switchcase 都允许任意表达式。

比如:

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 执行同样的代码:

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

类型很关键

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

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

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 分支。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值