循环语句

所谓循环就是指某段代码被重复执行的过程。

循环的本质就是以某个变量为起始值,然后不断产生变化量,慢慢靠近终止条件的过程。所以,循环需要具备三要素:

  1. 变量起始值
  2. 终止条件(没有终止条件,循环会一直执行,造成死循环)
  3. 变化量(用自增或者自减)

注意:循环内的弹窗有断点的效果

do-while语句

do-while 语句是一种后条件判断语句,即循环体中的代码执行后才会对退出条件进行求值。

换句话说:无论条件是否为真都会先进行循环体,也就是说循环体内的代码至少执行一次。

1do {
2  statement;
3} while (expression);
1let i = 0;
2do {
3  i += 2;
4} while (i < 10);

:::

使用场景

循环体代码在退出前至少要执行一次

while语句

while 语句是一种先条件判断语句,即先检测退出条件,再执行循环体内的代码。因此,while循环体内的代码有可能不会执行。

while跟if语句很像,都要满足小括号里的条件,只有当条件为true时才会执行代码块

while大括号里代码执行完毕后不会跳出,而是继续回到小括号里判断条件是否满足,若满足则继续执行大括号里面的代码,然后回到小括号判断条件,直到括号内条件不满足,即跳出。

1while (expression) statement;
1let i = 0;
2while (i < 10) {
3  i += 2;
4}

:::

for

for 语句也是一种先条件判断语句,只不过增加了进入循环之前的初始化代码,以及循环执行后要执行的表达式。

语法
1for(initialization; expression; post-loop-expression) statement;
1let count = 10;
2for (let i = 0; i < count; i++) {
3  console.log(i);
4}

以上代码在循环开始前定义了变量 i 的初始值为 0。然后求值条件表达式(i < count),如果求值结果为 true,则执行循环体。因此循环体也可能不会被执行。如果循环体被执行了,则循环后表达式也会执行,以便递增变量 i。for循环跟下面的while循环是一样的:

1let count = 10;
2let i = 0;
3while (i < count) {
4  console.log(i);
5  i++;
6}

**无法通过while循环实现的逻辑,同样也无法通过for循环实现。**因此for循环只是将循环相关的代码封装在了一起而已。

TIP

在for循环的初始化代码中,其实是可以不使用变量声明关键字的。不过,初始化定义的迭代器变量在循环执行完成后几乎不可能再用到了。因此,最清晰的写法是使用let声明迭代变量,这样就可以将这个变量的作用域限定在循环中。

初始化、条件表达式和循环后表达式都不是必须的。因此,下面这种写法可以创建一个无穷循环:

1for (;;) {
2  doSomething();
3}

如果只包含条件表达式,那么for循环实际上就变成了while循环:

1let count = 10;
2let i = 0;
3for (; i < count; ) {
4  console.log(i);
5  i++;
6}

for循环嵌套

1//一个循环里再套一个循环,一般用在for循环里
2for(外部声明记录循环次数的变量; 循环条件; 变化值){
3	for(内部声明记录循环次数的变量; 循环条件; 变化值){
4		循环体
5	}
6}

for循环和while循环的区别

  • 如果明确了循环的次数,推荐使用for循环

  • 如果不明确循环的次数,推荐使用while循环


for-in语句

for-in 语句是一种严格的迭代语句,用于枚举对象中的非符号键属性。

1for (property in expression) statement;
1// 遍历对象
2let obj = {
3  name: "小苏同学",
4  url: "xiaosutongxue.com"
5};
6for (const key in obj) {
7  // key是对象的属性,obj[key]是对象中属性key对应的值
8  if (obj.hasOwnProperty(key)) {
9    console.log(obj[key]);
10  }
11}
12
13// 遍历数组
14let arr = ['钢铁侠', '绿巨人', '蜘蛛侠'];
15for (const key in arr) {
16  // key是数组的索引,arr[key]是数组中索引key对应的值
17  console.log(key);	// 0 1 2
18  console.log(arr[key]);	// 钢铁侠 绿巨人 蜘蛛侠
19}

与for循环一样,这里控制语句中的const也不是必须的,但为了确保这个局部变量不被修改,推荐使用const。

ECMAScript中对象的属性是无序的,因此 for-in 语句不能保证返回对象的属性的顺序。换句话说,所有可枚举的属性都会返回一次,但返回的顺序可能会因浏览器而异。

如果 for-in 循环要迭代的变量是 nullundefined,则不执行循环体。


for-of语句

for-of 语句是一种严格的迭代语句,用于遍历可迭代对象的元素。

1for (property of expression) statement;

用来遍历 Arrays(数组)、Strings(字符串)、Maps(映射)、Sets(集合)等可迭代的数据结构。

for...in... 不同的是 for...of... 每次循环取其中的值而不是索引。

1// 遍历数组
2let arr = [1, 2, 3];
3for (const iterator of arr) {
4  console.log(iterator);	// 1 2 3
5}
6
7// 遍历字符串
8let str = "xiaosutongxue";
9for (const iterator of str) {
10  console.log(iterator);	// x i a o s u t o n g x u e
11}

与for循环一样,这里控制语句中的const也不是必须的,但为了确保这个局部变量不被修改,推荐使用const。

for-of 循环会按照可迭代对象的 next() 方法产生值的顺序迭代元素,如果尝试迭代的变量不支持迭代,则 for-of 语句会抛出错误。


标签语句

标签语句用于给语句加标签

1label: statement;

标签(label)为程序定义位置,可以使用continue/break跳到该位置。

1// i+n 大于 15 时退出循环
2outside: for (let i = 1; i <= 10; i++) {
3  inside: for (let n = 1; n <= 10; n++) {
4    if (n % 2 != 0) {
5      continue inside;
6    }
7    console.log(i, n);
8    if (i + n > 15) {
9      break outside;
10    }
11  }
12}

break 和 continue 语句

breakcontinue 语句为执行循环代码提供了更严格的控制手段。其中:

  • break 语句用于立即退出循环,强制执行循环后的下一条语句(循环体内 break后面的语句不再执行)。

  • continue 也用于立即退出循环,但会再次从循环顶部开始执行。(结束本次循环,继续下次循环)

1let num = 0;
2for (let i = 1; i < 10; i++) {
3  if (i % 5 == 0) {
4    break;
5  }
6  num++;
7}
8console.log(num); // 4
1let num = 0;
2for (let i = 1; i < 10; i++) {
3  if (i % 5 == 0) {
4    continue;
5  }
6  num++;
7}
8console.log(num); // 8

:::

breakcontinue 都可以使与标签语句一起使用,返回代码中特定的位置,这通常是在嵌套循环中。

1let num = 0;
2outermost: for (let i = 0; i < 10; i++) {
3  for (let j = 0; j < 10; j++) {
4    if (i == 5 && j == 5) {
5      break outermost;
6    }
7    num++;
8  }
9}
10console.log(num); // 55
1let num = 0;
2outermost: for (let i = 0; i < 10; i++) {
3  for (let j = 0; j < 10; j++) {
4    if (i == 5 && j == 5) {
5      continue outermost;
6    }
7    num++;
8  }
9}
10console.log(num); // 95

:::

with语句

with 语句的用途是将代码作用域设置为特定的对象。

1with (expression) statement;

使用 with 语句的主要场景是针对一个对象的反复操作,这时候将代码作用域设置为该对象能提供便利。

1let qs = location.search.substring(1);
2let hostName = location.hostname;
3let url = location.href;
4
5// 使用with语句的写法
6with (location) {
7  let qs = search.substring(1);
8  let hostName = hostname;
9  let url = href;
10}

这里 with 语句用于连接 location 对象。这意味着在这个语句内部,每个变量都会被认为是一个局部变量。如果没有找到该局部变量,则会搜索 location 对象,看它是否有一个同名的属性。如果有,则该变量会被求值为 location 对象的属性。

严格模式不允许使用 with 语句,否则会抛出错误。

with 语句影响性能且难于调试其中的代码,通常不推荐在产品代码中使用 with 语句。