JavaScript 中的各种循环

2025年01月09日00

JavaScript 中有很多循环,比如for语句、Array.prototype.forEach以及for-infor-offor-await-of语句。接下来结合规范学习总结它们。

for 语句

规范中,把运行时的for语句分为三种形式.

  1. for ( ; ; ) 基本形式
  2. for (var...) 带有 var 声明的形式
  3. for (let/const ...) 带块级作用域变量声明的形式

基本形式

运行时语义

  1. 如果 Expression1 存在
  • 如果是表达式,对其进行求值,然后被舍弃(禁止行副作用,如赋值)
  1. 如果 Expression2 存在
  • 则将其作为循环继续的条件
  • 不存在则无判断条件(即不会退出循环)
  1. 如果 Expression3 存在
  • 在当前循环体执行完后对其进行求值

带变量声明的形式

对于在for循环中进行变量声明的另外两种形式:

  • 对于 letconst 声明,每次循环迭代都会创建一个新的词法环境(LexicalEnvironment),绑定新的变量
  • 对于 var 声明,变量属于函数作用域,不随每次循环迭代创建
带变量声明的for statement

Array 中的循环

对于数组的绝大多数包含遍历的方法,内部逻辑都是: 首先获取数组的长度。于是在 forEachcallback

  1. 如果增加了数组项,访问到的也是旧数组的长度
  2. 如果在某个下标前修改了他,则后续访问的是修改后的值
  3. 如果删除数组中的某一项,由于会导致后续访问时某一项值为undefined,所以循环次数会减少(callback不会执行)
array.forEach执行逻辑

HasProperty: 判断 O 中 是否包含 P 这个属性键,如果包含则返回 true 否则返回 false。 一般用作检查 P 是否是对象 O 本身的属性或者从 O 的原型链上集成的属性。

所以一些面试问到 如何退出forEach循环,本身 forEach 内置函数正常情况下都会遍历整个数组,除开使用 for 或者 for-of(脱离题意)之外,只能考虑在数组的回调中抛出错误。当然,如果只是想不执行回调,也可以在callback中提前返回undefined

for-in/for-of/for-await-of

规范中是分为 ForIn/OfHeadEvaluationForIn/OfBodyEvaluation 两部分来解释的。

for-in

  1. 将目标值转换为对象
  • 首先将目标值 exprValue 转换为对象。如果 exprValue 是原始类型(如字符串、数字),则通过 ToObject 转换成对应的包装对象
  • 如果目标值是 nullundefined,则返回 Completion Record { [[Type]]: break, [[Value]]: empty, [[Target]]: empty }(即啥事也不干)
  1. 获取可枚举属性迭代器
  • 调用 EnumerateObjectProperties,它返回一个迭代器对象,该迭代器按顺序提供对象自身及其原型链上的 可枚举属性键
  1. 逐一迭代属性键
  • 每次循环,调用迭代器的 next() 方法获取下一个属性键
  1. 终止条件
  • 当迭代器返回 done: true 时,退出循环

for-of

基本上与 for-in 一致,区别在于循环体中获取的是 next().value 而非 next().

需要注意的是

  • 如果目标值是 null 或者 undefined,则会抛出 TypeError null/undefined is not iterable

for-await-of

for-of 主要区别在于使用的是 asyncIterator 获取迭代器.

  1. 获取异步迭代器
  • 调用目标对象的 @@asyncIterator 方法获取异步迭代器
  1. 等待异步值
  • 调用异步迭代器的 next(),返回 Promise
  • 使用 await 等待 Promise 完成,获取其 valuedone
  1. 执行循环体
  2. 终止条件
  • 当迭代器返回 done: true 时,循环终止

需要注意的是

  • for-await-of 必须在 async 函数内执行
  • 如果目标值是 undefinednull,则会抛出 TypeError Cannot read properties of undefined (reading 'Symbol(Symbol.asyncIterator)')