JavaScript 循环方法

JavaScript 循环方法

不涉及到具体绑定到 prototype 上的循环方式,即 XXXXX.prototype 中包含的循环方式(如 forEach, map)。

for

for 总共有三种循环方式,一个是传统的 for 循环体,一个是 for in,还有一种是 for of

传统 for

这个语法大多数其他的编程语言也有,JS 中主要是在于变量的声明,如:

// ES5
for (var i = 0; i < 10; i++) {
    
    
  console.log('es5');
}

// ES6
for (let i = 0; i < 10; i++) {
    
    
  console.log('es6');
}

const arr = [1, 2, 3];

for (let i = 0; i < arr.length; i++) {
    
    
  console.log(arr[i]);
}

这里语法没有什么特别大的区别,输出结果也都一致,主要区别就在于 varlet 造成的作用域和变量提升(hoisting)的问题。鉴于目前浏览器对于 ES6 的支持都挺好的,建议使用 let 而非 var

这里不能使用 const,因为使用 const 声明的变量无法被修改,所以这里也就无法被 increment,从而导致报错:

在这里插入图片描述

var, let, const 的异同可以查看这篇笔记:var, let, const 的区别与相同

另外一个比较有趣的写法,也是之前没有注意到的,就是省略所有变量声明的写法:

for (;;) {
    
    
  // do sth
}

这样会造成一个无限循环。

for...of

for...of 是一个 ES6 后实现的迭代方式,大多数情况下用来便利数组,不过它本身可以用来循环所有的 iterable 对象,其中包括:

  • 数组
  • 字符串
  • TypedArray
  • Map
  • Set
  • NodeList
  • arguments
  • generators
  • 用户自定义的 iterable 对象

总体来说如果是搭配 ES6 以后新创建的一些 objects 与特性,其灵活度甚至比起传统 for 循环还要高,唯一的局限就在于无法获取下标。

下面是比较常见使用 for...of 的语法:

const arr = [1, 2, 3, 4, 5];

for (const val of arr) {
    
    
  console.log(val);
}

const map = new Map([
  ['a', 1],
  ['b', 2],
  ['c', 3],
]);

for (const [key, val] of map) {
    
    
  console.log(key, val);
}

const set = new Set(['a', 1, 'b', '2', 2]);

for (const setV of set) {
    
    
  console.log(setV);
}

在这里插入图片描述

for...in

for...in 用于迭代对象中不包括 symbol 的可枚举字符串属性 enumerable string properties,并且,for...in 也可以用来迭代继承的可枚举字符串属性:

const obj = {
    
    
  a: 'a',
  b: 'b',
  c: 'c',
};

for (const enumerable in obj) {
    
    
  console.log(enumerable);
}

const obj2 = {
    
     d: 'd' };
obj2.__proto__ = obj;

for (const enumerable in obj2) {
    
    
  console.log(enumerable);
}

在这里插入图片描述

while

while 主要就分 whiledo-while,二者的区别不算太大,主要是 do-while 会至少运行一次再检测是否满足条件。

let i = 10;

while (i < 0) {
    
    
  console.log('i < 10');
}

do {
    
    
  console.log('at least log once');
} while (i < 10);

在这里插入图片描述

关键字

主要补一下 label……才发现原来 JS 也有啊……

break

break 可以用来打破当前的循环,换言之,如果在 nested loops 中,它会 break inner loop:

for (let i = 0; i < 5; i++) {
    
    
  console.log('i', i);
  for (let j = 0; j < 20; j++) {
    
    
    // 这里一旦 j > 1 就会跳出当前循环
    if (j > 1) break;
    console.log('j', j);
  }
}

在这里插入图片描述

continue

continue 会继续下一个循环,如:

for (let i = 0; i < 5; i++) {
    
    
  // 一旦 i > 2,就会跳过下面的代码,重新进入循环
  if (i > 2) continue;
  console.log('i', i);
  for (let j = 0; j < 20; j++) {
    
    
    if (j > 1) break;
    console.log('j', j, 'i', i);
  }
}

在这里插入图片描述

label

label 之前我没怎么用过……好像只有在汇编的时候碰到过。

其主要用途是将一个 label 绑定一个 expression,随后跳到对应的 label 上。虽然非循环体也可以使用 label,不过大多数情况下还是循环体中比较符合使用规律:

for (let i = 0; i < 3; i++) {
    
    
  let j = 3;
  outer: do {
    
    
    console.log(j);
    for (let k = 0; k < 5; k++) {
    
    
      // 一旦k === 3 就会跳到 outer,因为 outer 的条件不满足了,所以就会彻底终止 do-while 循环
      if (k === 3) {
    
    
        break outer;
      }
      console.log(k);
    }
    j++;
  } while (j < 3);
}

在这里插入图片描述

ES6 后的其他循环方式

map 可以使用其本身提供的 keys()values() 两个函数,set 则是只有 values。它们返回的都是 iterator,所以需要使用 iterator 的方法进行调用。

对象除了 for...in 之外还可以使用 Object.entries(), Object.keys(), Object.values() 的方式获取数组形式的键值对、键和值,因为返回的都是数组,所以可以使用传统的 for 循环。

the end

传统 for 循环写起来可能是最麻烦的,不过对于需要下标的循环来说灵活度也是最高的,在一些情况下确实能够解决 forEach 所带来的问题,不过传统 for 循环无法实现对于对象的循环。

for...of 的写法更加的简单,并且也可以使用 await 进行异步操作,并且搭配一些 ES6 后存在的 objects 与 attributes,其灵活性会更高,不过需要 index 的时候 for...of 就有它的局限性。

for...in 只能用来循环对象,关于什么时候使用获取对象的键值对的方法,可以参考这张表:

在这里插入图片描述

一些其他关于数组循环的笔记有:

其他的 reference:

猜你喜欢

转载自blog.csdn.net/weixin_42938619/article/details/130682632