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

相关推荐
WangHappy1 分钟前
不写 Canvas 也能搞定!小程序图片导出的 WebView 通信方案
前端·微信小程序
李剑一5 分钟前
要闹哪样?又出现了一款新的格式化插件,尤雨溪力荐,速度提升了惊人的45倍!
前端·vue.js
闲云一鹤13 分钟前
Git LFS 扫盲教程 - 你不会还在用 Git 管理大文件吧?
前端·git·前端工程化
阿虎儿1 小时前
React Context 详解:从入门到性能优化
前端·vue.js·react.js
颜酱1 小时前
理解二叉树最近公共祖先(LCA):从基础到变种解析
javascript·后端·算法
Sailing1 小时前
🚀 别再乱写 16px 了!CSS 单位体系已经进入“计算时代”,真正的响应式布局
前端·css·面试
FansUnion1 小时前
我如何用 Next.js + Supabase + Cloudflare R2 搭建壁纸销售平台——月成本接近 $0
javascript
喝水的长颈鹿2 小时前
【大白话前端 03】Web 标准与最佳实践
前端
爱泡脚的鸡腿2 小时前
Node.js 拓展
前端·后端
左夕3 小时前
分不清apply,bind,call?看这篇文章就够了
前端·javascript