JS 中的各种 for 循环

真是一坑未填又开一坑….现在阶段,for循环有4种,我们先把所有的 for 循环列出,一个一个的聊。

从MDN上边,找到了 四种 for 循环,分别是:forfor...infor...offor await...of

1. for 原始 for 循环语句

经典的 for 循环,所有新手一开始都会写的 demo 基本都会用到的 for 循环吧,我就不多讲了,上一个学生时代(伪)的*号金字塔吧。

const max = 5
for (let n = 1; n < max; n++) {
  let str = ''
  for (let i = 1; i < max - n; i++) {
    str += ' '
  }
  for (let j = 1; j < 2 * n; j++) {
    str += '*'
  }
  console.log(str);
}
//    *
//   ***
//  *****
// *******

2. for...in 为遍历对象属性而构建的 for 循环

for...in 语句以任意顺序遍历一个对象的除Symbol以外的可枚举属性。
啥?你问我 Symbol 是啥?看这里

上 demo 配合着来看,先是对象

const obj = { a: 1, b: 2, c: 3 };

for (let prop in obj) {
  console.log(prop);
}

// a
// b
// c

再看一下用它来遍历数组

const arr = ['a', 'b', 'c'];

for (let prop in arr) {
  console.log(prop);
}

// 0
// 1
// 2

可以看到,它遍历对象的属性名,MDN最后有一句:

“它最常用的地方应该是用于调试,可以更方便的去检查对象属性(通过输出到控制台或其他方式)”

????? ,可我实一般调试时都是直接把整个对象都打印出来啊

所以 for...in 是为遍历对象属性而构建的 for 循环,虽然数组可以用,但是并没有Dio用….

并且它会枚举所有属性,包含了被迭代的对象的原型,实际工作开发,这些对象很可能是不需要出现的属性,比如VueJS的 __ob_

虽然可以配合使用 hasOwnProperty() 来处理,但是太蛮烦了,最好用的场景可能就是这个同时输出键名和键值的场景

const triangle = {a: 1, b: 2, c: 3};

function ColoredTriangle() {
  this.color = 'red';
}

ColoredTriangle.prototype = triangle;

const obj = new ColoredTriangle();

for (let prop in obj) {
  if (obj.hasOwnProperty(prop)) {
    console.log(`obj.${prop} = ${obj[prop]}`);
  } 
}

// obj.color = red

3. for...of 遍历可迭代对象的可枚举属性

for...of 可迭代的对象就多了(包括 Array,Map,Set,String,TypedArray,arguments 对象,DOM 集合等等,但是 不包括Object 哦),在这些 可迭代 对象上创建一个迭代循环,调用自定义迭代钩子,并为每个不同属性的值执行语句,具体可以看MDN的文档。for…of - MDN

它与 for...in 的区别是什么?

主要区别在于它们的迭代方式:

  • for...in 语句以任意顺序迭代对象的可枚举属性。
  • for...of 语句遍历可迭代对象定义要迭代的数据。

配合着demo来看吧。

// 为对象和数组原型增加方法
Object.prototype.objCustom = function() {};
Array.prototype.arrCustom = function() {};

// 声明数组并赋值
let iterable = [3, 5, 7];
iterable.foo = 'hello';

// for...in 遍历输出属性名
for (let i in iterable) {
  console.log(i); // 0, 1, 2, "foo", "arrCustom", "objCustom"
}

// for...in 判断是否拥有属性并输出属性名
for (let i in iterable) {
  if (iterable.hasOwnProperty(i)) {
    console.log(i); // 0, 1, 2, "foo"
  }
}
// arrCustom和objCustom不会被输出,因为它们是继承的,并非自身的属性

// for..of 输出可迭代数据
for (let i of iterable) {
  console.log(i); // 3, 5, 7
  // 仅仅输出可迭代对象数组定义的元素值
}

每个对象将继承 objCustom 属性,并且作为 Array 的每个对象将继承 arrCustom 属性,因为将这些属性添加到 Object.prototypeArray.prototype
由于继承和原型链,对象 iterable 继承属性 objCustomarrCustom
所以 for...in 会遍历出所有属性名,包括数组元素的下标和继承下来的属性,而 for...of 只遍历了可迭代的数组元素值。


4. for await...of

ES9的内容???我先看看文档:

for await...of 语句创建一个循环,该循环遍历异步可迭代对象以及同步可迭代对象,包括: 内置的 String, Array,类似数组对象 (例如 argumentsNodeList),TypedArray, Map, Set 和用户定义的异步/同步迭代器。它使用对象的每个不同属性的值调用要执行的语句来调用自定义迭代钩子。

然后

类似于 await 运算符一样,该语句只能在一个 async function 内部使用。

简单的用 generator 举一个例子:

async function* asyncGenerator () {
  var i = 0;
  while (i < 3) {
    yield i++;
  }
}

(async function () {
  for await (num of asyncGenerator()) {
    console.log(num);
  }
})()

但是没有想到有食用的业务场景,可能循环的异步调用?
类似依次调用函数读取文件列表进行处理???等以后遇到了合适场景再展开了解吧。

以上