什么是javascript迭代器_for_of循环如何遍历可迭代对象【教程】

for-of循环仅适用于实现了[Symbol.iterator]方法的可迭代对象;数组、字符串、Map等原生可迭代,普通对象默认不可迭代,需用Object.keys()等转换或手动部署[Symbol.iterator]。

for-of 循环只能遍历实现了 [Symbol.iterator] 的对象

不是所有 JS 对象都能用 for...of 遍历。它只认「可迭代对象(iterable)」——即内部有 [Symbol.iterator] 方法、且该方法返回一个符合迭代器协议的对象。数组、StringMapSetTypedArrayargumentsNodeList 是原生可迭代的;普通对象({})默认不是。

常见错误:直接对 plain object 写 for...of,会报 TypeError: xxx is not iterable

  • 想遍历对象键值?用 Object.keys(obj)Object.entries(obj) 包一层再 for-of
  • 自定义类要支持 for-of?必须在原型上部署 [Symbol.iterator] 方法
  • Node.js 早期版本(Map.prototype.values() 返回值)可能不被 for-of 直接识别,需确认运行时环境

for...offor...in 的根本区别在哪

for...in 遍历的是对象的**可枚举属性名(字符串 key)**,包括原型链上的;for...of 遍历的是对象的**迭代值(value)**,只走自身实现的迭代协议,与属性名无关。

典型陷阱:for...in 遍历数组会得到索引字符串("0", "1"),还可能混入添加的非数字属性;而 for...of 拿到的是真实元素值(arr[0], arr[1]),更安全直观。

  • for...in 适合查对象结构(比如调试时看有哪些字段)
  • for...of 适合取数据(尤其配合 break/continueawait 使用)
  • 两者都不能保证遍历顺序对所有对象一致,但对数组、字符串、Map、Set,ES2015+ 规范已明确要求按插入顺序

如何让自定义对象支持 for...of

只需在对象(或其原型)上定义 [Symbol.iterator] 方法,返回一个对象,该对象有 next() 方法,每次调用返回 { value, done } 形式的迭代结果。

const counter = {
  from: 1,
  to: 3,
  [Symbol.iterator]() {
    let current = this.from;
    const last = this.to;
    return {
      next() {
        if (current <= last) {
          return { value: current++, done: false };
        }
        return { value: undefined, done: true };
      }
    };
  }
};

for

(const num of counter) { console.log(num); // 1, 2, 3 }
  • next() 必须是无参函数;带参数会被忽略(除非是 generator,但那是另一套机制)
  • done: true 后,后续调用 next() 应始终返回 { value: undefined, done: true }
  • 如果想复用逻辑,可以把迭代器逻辑抽成独立函数,多个对象共用

遇到 TypeError: xxx is not a function 怎么排查

这个错误常出现在你误以为某个对象可迭代,但它返回的 [Symbol.iterator]undefined 或非函数。例如:DOM 元素集合在低版本浏览器中可能没正确暴露迭代器;或你手动删了 Array.prototype[Symbol.iterator](极少见但可能)。

快速验证方式:

const obj = /* 你的对象 */;
console.log(typeof obj[Symbol.iterator]); // 应该是 "function"
console.log(obj[Symbol.iterator]());       // 应该返回一个有 next() 的对象
  • Node.js 中检查是否启用了 --harmony-iterator(v12 以前旧版本需要)
  • 使用 Babel 编译时,确保 @babel/preset-env 配置了目标环境,否则可能把 for...of 转成不兼容的代码
  • 某些库(如早期 Lodash)的包装对象(_.wrap() 等)不自动继承迭代器,需显式调用 .value() 获取底层数组再遍历

迭代器协议看着抽象,实际就是「提供一个标准接口让 for-of 知道怎么一步步取值」。真正容易卡住的地方,往往不是写错语法,而是没意识到某个对象根本没实现这个接口,或者环境不支持。