发布于 2026-01-06 9 阅读
0

控制流:入门指南 Switch 语句 循环 循环中断 循环继续 总结

控制流:入门指南

switch语句

循环

打破循环

持续循环

概括

图像

总有那么一些时候,你需要依靠自动化任务来运行代码。想想交通信号灯,它们控制着交通,免去了城市在每个十字路口都安排交警的麻烦。或者想想流水线,它以惊人的速度执行着繁琐的任务。

同样,条件语句和循环语句使我们能够编写高效的代码。之所以使用“控制流”这个术语,是因为解释器是从上到下逐步读取代码的。

当你写出一堆类似这样的语句时:

 let firstVar = 'dummy';
 let secondVar = 'bozo';
 let thirdVar = 'stoog';

 console.log(firstVar);
 console.log(secondVar);
 console.log(thirdVar);
Enter fullscreen mode Exit fullscreen mode

解释器从上到下读取代码并按顺序执行。如果我们不考虑用户会与我们的应用交互,这倒没什么问题。但与机器人不同,人类与应用的交互方式可能并非我们所期望的,因此我们必须通过设置条件来应对这种情况。

把条件语句想象成路上的岔路口。你可能已经熟悉其中一个条件语句——if 语句。让我们尝试在用户与我们的应用交互的场景中使用它。

如果/否则

假设我们受命为一家名为“宠物天堂”(Pet Nirvana)的宠物日托中心设计一个提交表单。首席执行官拉里·戴维斯想问潜在客户的问题之一是:“您有多少只宠物?”

var answer = prompt("how many pets do you have?");
alert(answer);
Enter fullscreen mode Exit fullscreen mode

专业提示:该prompt方法接收用户响应并返回用户的输入。我们可以用它来测试用户输入。以前,该alert方法曾用于测试输出,但console.log()现在已经取代了这一角色。

我们通常会假设用户会输入一个数字,但如果有人想输入一长串字符串来戏弄我们呢?

如果没有控制流,恶意用户可能会这样做:DROP/*you got jacked!*/users

这短短一行 SQL 代码就能删除数据库中的所有用户。这只是一个例子。实际上,只需要一个简单的字符串就能让我们的应用程序崩溃。

想象一下,如果我们想计算每位主人平均拥有的宠物数量,以便戴维斯先生知道他应该在宠物用品上花费多少钱。

不用担心函数部分。将下面的代码复制到编辑器中,然后尝试输入一个数字。

var pets = 35;
var owners = 15;
var petsPerOwner = average(pets, owners);
//======Pet Info Form
var answer = prompt("how many pets do you have?");
//============
updateAvg(answer) // update based on answer, add new owner

console.log(`There are now ${petsPerOwner} pets per owner at Pet Nirvana `)

//============
//Functions are hoisted up in JavaScript.
//We'll deal with 'em later

function average(total, number){
    return total / number;
}
function updateAvg(newNum){
  pets += Number(newNum); // register new pet(s)
  owners += 1 // register new owner
  petsPerOwner = Math.ceil(average(pets, owners)); // find new average, round up
}

Enter fullscreen mode Exit fullscreen mode

你应该得到一个比较接近整数的平均值。现在,尝试在提示符中插入一个随机字符串。

你应该看到“目前 Pet Nirvana 每位主人拥有的宠物数量为 NaN”。

专业提示:具体错误源于 `Number()` 函数。该函数会将字符串类型的数字强制转换'3'为数字类型。我们接收到的用户输入通常都是字符串,因此在需要数字时,`Number
( )` 函数非常有用。但如果输入是普通的单词字符串,而我们试图将其强制转换为数字,则会得到错误3Number()NaN

这看起来或许没什么大不了,但在现实世界中却是一场灾难。仅仅因为无法筛选数据,我们就失去了获取重要信息的途径。

我们必须对我们想要处理的数据拥有控制权。

如果/否则

幸好我们有 if/else 语句。

var answer = prompt("how many pets do you have?");
if(isNaN(answer)){
    alert("Error: input a number");
}else{
  updateAvg(answer) // update based on answer, add new owner
  console.log(`There are now ${petsPerOwner} pets per owner at Pet Nirvana `)
}
Enter fullscreen mode Exit fullscreen mode

我们不再随意接收任何响应,而是通过检查答案是否为数字来控制数据流。还记得我们之前的NaN错误吗?当你尝试对字符串执行不兼容的算术运算符时就会出现这个错误。如果条件为真,if 语句内的任何代码块都会自动执行。

注意:无需编写,isNaN(answer) == true因为 if 语句可以判断一个值的真假。

"hello" / 4; //> NaN
Enter fullscreen mode Exit fullscreen mode

有一个内置函数可以isNaN()检查数据类型是否为数字。如果数据类型不是数字,则返回 true;否则,返回 false。

为了更好地理解,让我们把刚才写的代码转换成伪代码。

/*
If the answer is not a number
     output an error
Else(otherwise)
    update the average
*/

Enter fullscreen mode Exit fullscreen mode

短路

还有另一种控制数据流的方法。我们可以绕过“或”运算符。

 isNaN(answer) || (petsPerOwner = updateAvg(answer));
console.log(`There are now ${petsPerOwner} pets per owner at Pet Nirvana `);
Enter fullscreen mode Exit fullscreen mode

OR 运算符会查找第一个真值。找到真值后,它会跳出条件判断。因此,如果答案不是数字,我们就无需更新平均值。

问题在于它answer仍然保留着不需要的值,限制了我们后续对该变量的操作。你还会注意到,我们无法向用户提供任何反馈。虽然短路 OR 运算符是个巧妙的技巧,但它并非控制数据流的最佳方法。

否则如果

如果我们想检查两个以上的可能性呢?如果宠物天堂的首席执行官还想提醒宠物主人,目前公司每位主人最多只能饲养三只宠物呢?这样一来,我们不仅需要检查用户输入的数据类型,还需要提醒饲养超过四只宠物的主人注意宠物数量限制。

使用 else if 语句会很有用。你可以根据需要将多个 else if 语句串联起来。

if(/*first condition*/){

}else if(/*second condition*/){

}else if(/*third condition*/){

}
Enter fullscreen mode Exit fullscreen mode

为什么我们不先尝试用伪代码来编写解决方案,然后再开始编写代码呢?

/*
If the answer is not a number
     output an error
Else if the answer is greater than three     
    warn the user that they have too many pets
Else(otherwise)
    update the average
*/

Enter fullscreen mode Exit fullscreen mode

让我们在代码中测试一下。当你输入一个大于 3 的数字时,应该会收到警告。

var answer = prompt("how many pets do you have?");
if(isNaN(answer)){
    alert("Error: input a number");
}else if(Number(answer) > 3){
  alert("Sorry, we currently only accept 3 pets");
}
else{
  updateAvg(answer) // update based on answer, add new owner
  console.log(`There are now ${petsPerOwner} pets per owner at Pet Nirvana `)
}

Enter fullscreen mode Exit fullscreen mode

任务

哦,哦。你和你的客户之间沟通出了问题。显然,他希望即使宠物主人的宠物总数超过限制,平均宠物数量也应该更新,但他想在更新之前先询问用户是否同意这个限制。

已为您提供伪代码。

/*
Else if the answer is greater than three   
  Prompt the user and ask if they're ok with the limit
  If the prompt equals yes
     update the average

*/

Enter fullscreen mode Exit fullscreen mode

switch语句

在使用 if 语句的过程中,你可能会遇到以下类型的代码:

if (x == "case 1") runThis();
else if (x == "case 2") runThat();
else if (x == "case 3") runThis();
else if (x == "case 4") runThat();
Enter fullscreen mode Exit fullscreen mode

如果要处理这么多案例,使用名为“控制流结构”的工具可能会更好switch

一个基本的 switch 语句以初始值开始,然后提供带有可选默认值的 case 块。

case语句其实就是更易于阅读的if语句。

let greeting = 'hello'
switch(greeting){
  case 'hello': // is the same as if(greeting === 'hello')
    //code goes here
    //break

  default: // is the same as else
}

Enter fullscreen mode Exit fullscreen mode

这里有一个更详细的例子供你参考。

let number = 2;

switch(number) {
  case 1:
    console.log("this is one");
    break;
  case 2:
    console.log("this is two");
    break;
  case 3:
    console.log("this is three");
    break;
  default:
    console.log("I can't count past three.");
}

//can you guess what the result will be?

Enter fullscreen mode Exit fullscreen mode

break 关键字至关重要。如果省略它们,即使条件满足,switch 语句也会继续执行,自动执行下一个 case 代码块,直到遇到 break 关键字或所有 case 代码块都执行完毕为止。

所以,如果我们省略了“ breakin” case 2:,就会得到:

"this is two"
"this is three"
Enter fullscreen mode Exit fullscreen mode

把 switch 语句想象成一条管道。break 语句就像堤坝,防止管道泄漏到其他部分。

关于 switch 语句,还有一点需要注意,那就是它可以对 case 进行分组。让我们扩展一下问候示例,来展示我们的 case 链。


switch(prompt('greet me!')){
  case 'hello':
  case 'hi':
  case 'yo':
    console.log("Hey? What's up?");
    break;
  default:
    console.log("I don't speak your lingo.");
}

Enter fullscreen mode Exit fullscreen mode

循环

现在我们知道如何控制输入的数据,但是如何控制发送给用户的数据呢?

戴维斯先生现在想为他的经纪人添加一个评分系统。他希望在他们的个人资料名称下方显示星级。

我们可以手动渲染所有星星……

//you can see that Becky has accumulated a rounded average of four stars
var becky = {name:'Becky Star', stars: 4}

//====Profile
//Mock profile name
console.log(becky.name)
//we can render our stars four times
render() + render() + render() + render();
//====
//Dummy render function
function render(){
  return '*';
}

Enter fullscreen mode Exit fullscreen mode

while 循环

或者我们可以使用while循环。while 循环会检查条件是否为真,如果为真,则会一直执行代码块,直到条件为假为止。请确保你的循环最终能够产生假值。否则,你就会陷入无限循环。

// you usually have to set a counter and either decrement or increment it till it satisfies the condition.
counter = 4;

while(counter != 0){
  console.log(counter);
  --counter //we decrease the counter by 1
}

Enter fullscreen mode Exit fullscreen mode

激发你的创造力。使用 while 循环渲染一行四颗星。输出结果应如下所示:'****'

提示:计数器编号和星星数量都很重要。

提示:加号等于运算符会很有用。

do while 循环与 while 循环类似,区别在于 do while 循环保证代码块在第一次循环时就会执行。

这就像在说,“一定要先执行这个(这段代码块)”。现在,当我的条件为真时,继续执行该代码块中的内容。

让我们重新审视一下宠物编号提示,并使用 do while 循环重写它。

let answer;
do {
  answer = prompt("how many pets do you have?");

}while(isNaN(answer))

Enter fullscreen mode Exit fullscreen mode

如果用户不输入数字,这段代码会不断提示用户输入信息。

让我们在循环中添加一个条件,以加强我们对信息的控制。

let answer;
do {
  answer = prompt("how many pets do you have?");
  if(isNaN(answer)){
     alert("error: enter a number");
  }
}while(isNaN(answer))

Enter fullscreen mode Exit fullscreen mode

现在我们已经创建了一个反馈循环,可以提醒用户他们的错误,并允许他们立即纠正错误。

for 循环

简单来说,for 循环就是一个带有“电池”的 while 循环。你知道你需要在循环外部设置一个计数器,然后确保它不断递减或递增吗?

使用 for 循环,您可以将所有内容都设置到一个参数中()

/* first you set the counter*/
//var x = 4;
/* then you set the condition*/
//x != 0;
/*finally, you decrement or increment
depending on your condition
*/
//--x
//Now let's install the batteries
for(var x = 4; x!= 0; --x){
  //we're ready to loop
}
Enter fullscreen mode Exit fullscreen mode

还记得你之前要做的渲染任务吗?这里是用 for 循环的解决方案。

//we can see here that Becky has accumulated a rounded total of four stars
var becky = {name:'Becky Star', stars: 4}
var starRow = '';
//====Profile
//Mock profile name
console.log(becky.name)
//rendering with the for loop
for(cnt = becky.stars; cnt != 0; --cnt){
  starRow += render();
}
starRow; // > '****'

//Dummy render function
function render(){
  return '*'
}

Enter fullscreen mode Exit fullscreen mode

打破循环

循环会一直运行,直到条件为假。有时我们可能想要像电影《盗梦空间》那样,使用关键字跳出循环break

//this is a potential infinite loop
while(true){
  console.log("I'm free!");
  break; // phew
}

Enter fullscreen mode Exit fullscreen mode

你可能会遇到需要使用嵌套 for 循环的问题。

var matrix = [[1,2,3],[4,5,6],[7,8,9]];
//prints 1,2,3,4...
for(var outer=0;outer < matrix.length; ++outer){
   for(var inner=0;inner < matrix.length; ++inner){
    console.log(matrix[outer][inner])   
   }
}

Enter fullscreen mode Exit fullscreen mode

在内层 for 循环中编写 break 语句会中断内层循环,但外层循环会继续运行。

var matrix = [[1,2,3],[4,5,6],[7,8,9]];
//prints 1,2,3,4...
for(var outer=0;outer < matrix.length; ++outer){
   for(var inner=0;inner < matrix.length; ++inner){
      if(matrix[outer][inner] === 2){
        break;
      }   
   }
}

Enter fullscreen mode Exit fullscreen mode

如果你想彻底摆脱所有循环,你需要给循环添加标签。在 for 循环名前加上你想要的任何名称,后面跟一个冒号。然后,当你准备跳出循环时,在 break 关键字后面加上你的标签名称。

labelName: for(){
  for(){
    break labelName;
  }  
}
Enter fullscreen mode Exit fullscreen mode

这是我们修改后的嵌套循环。

var matrix = [[1,2,3],[4,5,6],[7,8,9]];
//the for loop can start on a newline
outer:
for(var outer=0;outer < matrix.length; ++outer){
   for(var inner=0;inner < matrix.length; ++inner){
      if(matrix[outer][inner] === 2){
        break outer;
      }   
   }
}

Enter fullscreen mode Exit fullscreen mode

持续循环

continue 指令允许我们跳过循环中的某些步骤。或许这个指令应该叫做 skip,但没办法,我们姑且就叫 continue 吧。

for (let i = 0; i < 10; i++) {
// if i is even, skip the rest of the code.
  if (i % 2 == 0) continue;

  console.log(i); // 1, 3, 5, 7, 9
}
Enter fullscreen mode Exit fullscreen mode

专业提示:如果代码块可以用一行写完,则不需要花括号。

概括

我们攻克了if/else if/else语句,解决了switch语句问题,并理清了 `if`、`if`whiledo while`if` 之间的关系for loops。我们还学习了如何跳出循环以及如何继续循环。接下来,我们将学习 JavaScript 程序如何围绕函数展开。

文章来源:https://dev.to/howtocodejs/control-flow-the-beginners-guide-3mp9