JS 迭代器是什么东西

JS 迭代器是什么东西

为什么我们能用 for...of 遍历数组?为什么展开运算符 ... 能把对象展开?这一切都源于 JavaScript 中的迭代器机制。

迭代器:数据遍历的秘密武器

想象一下,你在图书馆看书,图书管理员一本本把书递给你,直到没有更多书为止------这就是迭代器的工作方式。迭代器(Iterator) 是 JavaScript 中一种特殊的对象,它提供了一种统一的机制来遍历各种数据结构。

迭代器协议

迭代器遵循一个简单的协议:它必须实现一个 next() 方法,每次调用返回一个包含两个属性的对象:

yaml 复制代码
JavaScript
{
  value: 当前值,
  done: 是否迭代完成
}

来看一个最简迭代器实现:

lua 复制代码
JavaScript
function createCounter(max) {
  let count = 0;
  
  return {
    next() {
      if (count < max) {
        return { value: count++, done: false };
      }
      return { value: undefined, done: true };
    }
  };
}

const counter = createCounter(3);
console.log(counter.next()); // { value: 0, done: false }
console.log(counter.next()); // { value: 1, done: false }
console.log(counter.next()); // { value: 2, done: false }
console.log(counter.next()); // { value: undefined, done: true }

这个计数器每次调用 next() 返回递增数字,直到达到最大值。

可迭代对象:迭代器的生产工厂

要使数据结构可遍历,它必须是可迭代对象(Iterable) 。可迭代对象必须实现 @@iterator 方法(通过 Symbol.iterator 访问):

kotlin 复制代码
JavaScript
const myIterable = {
  data: [10, 20, 30],
  [Symbol.iterator]() {
    let index = 0;
    
    return {
      next: () => {
        if (index < this.data.length) {
          return { value: this.data[index++], done: false };
        }
        return { done: true };
      }
    };
  }
};

// 现在可以用 for...of 遍历了
for (const value of myIterable) {
  console.log(value); // 依次输出 10, 20, 30
}

内置可迭代对象

JavaScript 中许多内置对象原生支持迭代:

arduino 复制代码
JavaScript
// 数组
const arr = [1, 2, 3];
for (const num of arr) {
  console.log(num);
}

// 字符串
const str = "你好";
for (const char of str) {
  console.log(char); // 输出 "你" 和 "好"
}

// Map
const map = new Map([['a', 1], ['b', 2]]);
for (const [key, value] of map) {
  console.log(key, value);
}

// NodeList
document.querySelectorAll('div').forEach(node => {
  // NodeList 也是可迭代的
});

迭代器的实际应用场景

1. 自定义数据结构的遍历

ini 复制代码
JavaScript
class Matrix {
  constructor(width, height, content = []) {
    this.width = width;
    this.height = height;
    this.content = content;
  }
  
  [Symbol.iterator]() {
    let row = 0;
    let col = 0;
    
    return {
      next: () => {
        if (row === this.height) {
          return { done: true };
        }
        
        const value = {
          x: col,
          y: row,
          value: this.content[row * this.width + col]
        };
        
        col++;
        if (col === this.width) {
          col = 0;
          row++;
        }
        
        return { value, done: false };
      }
    };
  }
}

const matrix = new Matrix(2, 2, [1, 2, 3, 4]);
for (const {x, y, value} of matrix) {
  console.log(`(${x},${y}): ${value}`);
}
// (0,0): 1
// (1,0): 2
// (0,1): 3
// (1,1): 4

2. 解构赋值与展开运算符

迭代器让这些操作成为可能:

csharp 复制代码
JavaScript
// 数组解构
const [first, second] = [10, 20, 30];

// 字符串解构
const [a, b] = "AB";

// 展开运算符
const newArray = [...'hello']; // ['h','e','l','l','o']

3. 异步迭代器(高级特性)

ES2018 引入了异步迭代器,用于处理异步数据流:

javascript 复制代码
JavaScript
async function* asyncGenerator() {
  yield await Promise.resolve(1);
  yield await Promise.resolve(2);
  yield await Promise.resolve(3);
}

(async () => {
  for await (const value of asyncGenerator()) {
    console.log(value); // 1, 2, 3
  }
})();

迭代器使用注意事项

  1. 单向性:迭代器是一次性用品,遍历后不能重置

    ruby 复制代码
    JavaScript
    const arr = [1, 2, 3];
    const it = arr[Symbol.iterator]();
    
    it.next(); // { value: 1, done: false }
    it.next(); // { value: 2, done: false }
    it.next(); // { value: 3, done: false }
    it.next(); // { done: true }
    
    // 无法重置,需要重新获取迭代器
  2. 部分消费:可以只使用部分迭代结果

    javascript 复制代码
    JavaScript
    function* generator() {
      yield 1;
      yield 2;
      yield 3;
    }
    
    const [first] = generator(); // first = 1
  3. 无限迭代器:注意避免无限循环

    javascript 复制代码
    JavaScript
    function* infinite() {
      let index = 0;
      while (true) {
        yield index++;
      }
    }
    
    // 使用时要加入中断条件
    for (const num of infinite()) {
      if (num > 5) break;
      console.log(num);
    }

迭代器 vs 类数组

常见误区是把类数组当作可迭代对象:

javascript 复制代码
JavaScript
// 类数组对象(有 length 和索引)
const arrayLike = {
  0: 'a',
  1: 'b',
  length: 2
};

// 错误!类数组不可迭代
// for (const item of arrayLike) { ... } 

// 解决方案:
// 1. 转换为数组
const realArray = Array.from(arrayLike);

// 2. 添加迭代器
arrayLike[Symbol.iterator] = function() {
  let index = 0;
  return {
    next: () => {
      return index < this.length 
        ? { value: this[index++], done: false }
        : { done: true };
    }
  };
};

总结

JS 迭代器是 JavaScript 中强大的抽象机制:

  1. 提供统一的遍历接口(for...of, ... 等)
  2. 让自定义数据结构具备可迭代能力
  3. 支持异步数据流处理(异步迭代器)
  4. 广泛应用于数组操作、解构赋值等场景

理解迭代器不仅能让你写出更优雅的代码,还能揭开 JavaScript 内部运作的神秘面纱。当你下次使用 for...of 循环时,不妨想想背后默默工作的迭代器对象!

迭代器不只是工具,更是连接数据与操作的桥梁。掌握它,让你的 JavaScript 之旅更上一层楼。

相关推荐
天平1 小时前
油猴脚本创建webworker踩坑记录
前端·javascript·typescript
原则猫3 小时前
前端基础大厦
前端
陈随易4 小时前
编程语言级别的Skill市场,AI Agent 的未来形态
前端·后端·程序员
SoaringHeart5 小时前
Flutter进阶:基于 EasyRefresh 的下拉刷新封装 n_easy_refresh_mixin.dart
前端·flutter
IT_陈寒6 小时前
Vite的热更新突然不香了,排查三小时差点砸键盘
前端·人工智能·后端
子兮曰7 小时前
Agency-Agents 深度解析:400+ AI 专家的"梦之队"如何重塑开发工作流
前端·后端·vibecoding
山河木马7 小时前
渲染管线-计算得到gl_Position(顶点着色器)之后续GPU流程
javascript·webgl·图形学
竹林8188 小时前
用 The Graph 查询链上数据实战:从手搓 RPC 到 Subgraph,我的 NFT 项目数据加载快了 10 倍
前端·javascript
妙码生花8 小时前
从 PHP 到 AI + Golang,程序员自救转型手记(十九):点选验证码代码逐行目检
前端·后端·go
Awu12279 小时前
⚡从零开发 Agent CLI(五)实现一个可治理、可扩展的工具系统
前端·人工智能·claude