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 之旅更上一层楼。

相关推荐
Carlos_sam18 分钟前
OpenLayers:封装一个自定义罗盘控件
前端·javascript
前端南玖28 分钟前
深入Vue3响应式:手写实现reactive与ref
前端·javascript·vue.js
wordbaby1 小时前
React Router 双重加载器机制:服务端 loader 与客户端 clientLoader 完整解析
前端·react.js
tactfulleaner1 小时前
手撕MHA、MLA、MQA、GQA
面试
itslife1 小时前
Fiber 架构
前端·react.js
3Katrina1 小时前
妈妈再也不用担心我的课设了---Vibe Coding帮你实现期末课设!
前端·后端·设计
hubber1 小时前
一次 SPA 架构下的性能优化实践
前端
可乐只喝可乐2 小时前
从0到1构建一个Agent智能体
前端·typescript·agent
Muxxi2 小时前
shopify模板开发
前端
Yueyanc2 小时前
LobeHub桌面应用的IPC通信方案解析
前端·javascript