来一起循环

循环, 就与这些:popular breakfast cereals, roller coasters and musical production一样。类似存在于编程中.编程中的循环也是一直重复着去做一件事 - 此处循环便是编程中的术语。

让我们来想一下下图,这位农夫考虑为他的家庭做一周的食物计划,他或许就需要执行一段循环:

一段循环通常需要一个或多个条件:

  • 一个开始条件,它被初始化为一个特定的值 - 这是循环的起点("开始:我没有食物”,上面)。
  • 一个结束条件,这是循环停止的标准 - 通常计数器达到一定值。 以上所说的“我有足够的食物”吗? 假设他需要10份食物来养活他的家人。
  • 一个迭代器,这通常在每个连续循环上递增少量的计数器,直到达到退出条件。 我们以前没有明确说明,但是我们可以考虑一下农民能够每小时收集2份食物。 每小时后,他收集的食物量增加了两倍,他检查他是否有足够的食物。 如果他已经达到10分(退出条件),他可以停止收集回家。

在 伪代码 中,这看起来就像下面这样:

loop(food = 0; foodNeeded = 10) {
  if (food = foodNeeded) {
    exit loop;
    // 我们有足够的食物了,回家吧。
  } else {
    food += 2; // 花一个小时多收集两个食物。
    // 循环将会继续执行。
  }
}

所以需要的食物量定为10,农民目前的数量为0。在循环的每次迭代中,我们检查农民的食物量是否等于他需要的量。 如果是这样,我们可以退出循环。 如果没有,农民花一个小时收集两部分食物,循环再次运行。

为何?

在这一点上,您可能会了解循环中的高级概念,但您可能会认为“好的,但是,这有助于我编写更好的JavaScript代码?” 正如我们前面所说,循环与所做的事情都是一样的,这对于快速完成重复任务是非常有用的。

循环的每个连续迭代的代码将略有不同,这意味着您可以完成相同但略有不同的任务的全部负载 。如果您有很多不同的计算要做, 做不同的一个,不一样的一个又一个!

让我们来看一个例子来完美地说明为什么循环是一件好事。 假设我们想在元素上绘制100个随机圆(按更新按钮一次又一次地运行示例以查看不同的随机集):

您现在不需要理解所有代码,但我们来看看实际绘制100个圆的那部分代码:

for (var i = 0; i < 100; i++) {
  ctx.beginPath();
  ctx.fillStyle = 'rgba(255,0,0,0.5)';
  ctx.arc(random(WIDTH), random(HEIGHT), random(50), 0, 2 * Math.PI);
  ctx.fill();
}
  • random(),在前面的代码中定义过了,返回一个 0 到 x-1 间的整数。
  • WIDTHHEIGHT 浏览器内部窗口的宽度和高度。

您应该有一个基本的想法 - 我们使用一个循环来运行这个代码的100次迭代,其中每一个在页面上的随机位置绘制一个圆。 无论我们绘制100个圆,1000还是10,000,所需的代码量将是相同的。 只有一个数字必须改变。

如果我们在这里没有使用循环,我们必须为我们想要绘制的每个圆重复以下代码:

ctx.beginPath();
ctx.fillStyle = 'rgba(255,0,0,0.5)';
ctx.arc(random(WIDTH), random(HEIGHT), random(50), 0, 2 * Math.PI);
ctx.fill();

这将非常无聊而且很难维持高速。 循环真的相当好用!

循环的标准

我们开始探索一些特定的循环结构。 第一个,你将使用大部分时间,是for循环 - 这有以下语法:

for (initializer; exit-condition; final-expression) {
  // code to run
}

我们有:

  1. 关键字for,后跟一些括号。
  2. 在括号内,我们有三个项目,以分号分隔:
    1. 一个初始化器 - 这通常是一个设置为一个数字的变量,它被递增来计算循环运行的次数。它也有时被称为计数变量
    2. 一个退出条件 -如前面提到的,这个定义循环何时停止循环。这通常是一个表现为比较运算符的表达式,用于查看退出条件是否已满足的测试。
    3. 一个最终条件 -这总是被判断(或运行),每个循环已经通过一个完整的迭代消失时间。它通常用于增加(或在某些情况下递减)计数器变量,使其更接近退出条件值。
  3. 一些包含代码块的花括号 - 每次循环迭代时都会运行这个代码。

我们来看一个真实的例子,所以我们可以看出这些做得更清楚。

var cats = ['Bill', 'Jeff', 'Pete', 'Biggles', 'Jasmin'];
var info = 'My cats are called ';
var para = document.querySelector('p');

for (var i = 0; i < cats.length; i++) {
  info += cats[i] + ', ';
}

para.textContent = info;

这给我们以下输出:My cats are called Bill, Jeff, Pete, Biggles, Jasmin。

这显示了一个循环用于迭代数组中的项目,并与每个项目进行一些操作 - JavaScript中非常常见的模式。 这里:

  1. 迭代器i从0开始(var i = 0)。
  2. 循环将会一直运行直到它不再小于猫数组的长度。 这很重要 - 退出条件显示循环仍然运行的条件。 所以在这种情况下,仍然是真的,循环仍然运行。
  3. 在循环中,我们将当前的循环项(cats[i]cats[当前下标的任何东西])以及逗号和空格连接到info变量的末尾。 所以:
    1. 在第一次运行中,i = 0,所以cats[0] +','将被连接到info("Bill")上。
    2. 在第二次运行中,i = 1,所以cats[1] +','将被连接到info("Jeff")上。
    3. 等等。 每次循环运行后,1将被添加到i(i ++),然后进程将再次启动。
  4. 当等于cats.length时,循环将停止,浏览器将移动到循环下面的下一个代码位。

我们留下的一个小问题是最后的输出句子形式不是很好:My cats are called Bill, Jeff, Pete, Biggles, Jasmin。

我们想改变最后循环迭代中的连接,以便在句子末尾没有逗号。 我们可以在for循环中插入一个条件来处理这种特殊情况:

for (var i = 0; i < cats.length; i++) {
  if (i === cats.length - 1) {
    info += 'and ' + cats[i] + '.';
  } else {
    info += cats[i] + ', ';
  }
}

使用break退出循环

如果要在所有迭代完成之前退出循环,可以使用break语句。 当我们查看switch语句时,我们已经在上一篇文章中遇到过这样的情况 。当switch语句中符合输入表达式的情况满足时,break语句立即退出switch语句并移动到代码之后。

与循环相同 - break语句将立即退出循环,并使浏览器移动到跟随它的任何代码。

说我们想搜索一系列联系人和电话号码,只返回我们想要找的号码? 首先,一些简单的HTML - 一个文本,允许我们输入一个名称来搜索,一个元素来提交搜索,以及一个

元素显示结果:




然后是JavaScript:

var contacts = ['Chris:2232322', 'Sarah:3453456', 'Bill:7654322', 'Mary:9998769', 'Dianne:9384975'];
var para = document.querySelector('p');
var input = document.querySelector('input');
var btn = document.querySelector('button');

btn.addEventListener('click', function() {
  var searchName = input.value;
  input.value = '';
  input.focus();
  for (var i = 0; i < contacts.length; i++) {
    var splitContact = contacts[i].split(':');
    if (splitContact[0] === searchName) {
      para.textContent = splitContact[0] + '\'s number is ' + splitContact[1] + '.';
      break;
    } else {
      para.textContent = 'Contact not found.';
    }
  }
});
  1. 首先我们有一些变量定义 - 我们有一个联系信息数组,每个项目是一个字符串,包含一个以冒号分隔的名称和电话号码。
  2. 接下来,我们将一个事件监听器附加到按钮(btn)上,这样当按下它时,运行一些代码来执行搜索并返回结果。
  3. 我们将输入的值输入到一个名为searchName的变量中,然后清空文本输入并重新对准它,准备进行下一个搜索。
  4. 现在有趣的部分,for循环:
    1. 我们的计数器开始时为在0,直到计数器不再小于contacts.length,并在循环的每次迭代之后将i递增1。
    2. 在循环中,我们首先将当前联系人(contacts [i])拆分为冒号字符,并将生成的两个值存储在名为splitContact的数组中。
    3. 然后,我们使用条件语句来测试splitContact [0](联系人姓名)是否等于输入的searchName。 如果是,我们在段落中输入一个字符串来报告联系人的号码,并使用break来结束循环。
  5. (contacts.length-1) 迭代后,如果联系人姓名与输入的搜索不符,则段落文本设置为“未找到联系人”,循环继续迭代。

使用continue跳过迭代

continue语句以类似的方式工作,而不是完全跳出循环,而是跳过循环的下一个循环。 我们来看另外一个例子,它把一个数字作为一个输入,并且只返回开平方之后为整数的数字(整数)。

HTML与最后一个例子基本相同 - 一个简单的文本输入和一个输出段落。 JavaScript也是一样的,虽然循环本身有点不同:

var num = input.value;

for (var i = 1; i <= num; i++) {
  var sqRoot = Math.sqrt(i);
  if (Math.floor(sqRoot) !== sqRoot) {
    continue;
  }

  para.textContent += i + ' ';
}
  1. 在这种情况下,输入应为数字(num)。 for循环给定一个从1开始的计数器(在这种情况下,我们对0不感兴趣),一个退出条件,当计数器大于输入num时循环将停止,并且迭代器的计数器将每次增加1。
  2. 在循环中,我们使用Math.sqrt(i)找到每个数字的平方根,然后通过测试平方根是否是一个整数,当它被四舍五入到最接近的整数时,它是否与自身相同(这是Math.floor(...)对传递的数字是什么)。
  3. 如果平方根和四舍五入的平方根不相等(!==),则表示平方根不是整数,因此我们对此不感兴趣。 在这种情况下,我们使用continue语句跳过下一个循环迭代,而不在任何地方记录该数字。
  4. 如果平方根是一个整数,我们完全跳过if块,所以continue语句不被执行; 相反,我们将当前i值加上一个空格连接到段落内容的末尾。

while语句和do ... while语句

for 不是JavaScript中唯一可用的循环类型。 实际上还有很多其他的,而现在你不需要理解所有这些,所以值得看几个人的结构,这样你就可以在稍微不同的方式识别出相同的功能。

首先,我们来看看while循环。 这个循环的语法如下所示:

initializer
while (exit-condition) {
  // code to run

  final-expression
}

除了在循环之前设置初始化器变量,并且在运行代码之后,循环中包含final-expression,而不是这两个项目被包含在括号中,这与以前的for循环非常类似。 退出条件包含在括号内,前面是while关键字而不是for。

同样的三个项目仍然存在,它们仍然以与for循环中相同的顺序定义 - 这是有道理的,因为您必须先定义一个初始化器,然后才能检查它是否已到达退出条件; 在循环中的代码运行(迭代已经完成)之后,运行最后的条件,这只有在尚未达到退出条件时才会发生。

我们再来看看我们的猫列表示例,但是重写了一个while循环:

var i = 0;

while (i < cats.length) {
  if (i === cats.length - 1) {
    info += 'and ' + cats[i] + '.';
  } else {
    info += cats[i] + ', ';
  }

  i++;
}


do...while循环非常类似但在while后提供了终止条件

initializer
do {
  // code to run

  final-expression
} while (exit-condition)

在这种情况下,在循环开始之前,初始化程序先重新开始。 do关键字直接在包含要运行的代码的花括号和终止条件之前。

这里的区别在于退出条件是一切都包含在括号中,而后面是一个while关键字。 在do ... while循环中,花括号中的代码总是在检查之前运行一次,以查看是否应该再次执行(在while和for中,检查首先出现,因此代码可能永远不会执行)。

我们再次重写我们的猫列表示例,以使用do...while循环:

var i = 0;

do {
 if (i === cats.length - 1) {
   info += 'and ' + cats[i] + '.';
 } else {
   info += cats[i] + ', ';
 }

 i++;
} while (i < cats.length);