理解 JavaScript 中的迭代协议和迭代器协议

在 JavaScript 中,迭代协议和迭代器协议是两个重要的概念,它们定义了对象如何被迭代以及如何生成一系列值。本文将详细介绍这两个协议,并通过代码示例帮助理解它们的实际应用。


什么是迭代协议?

迭代协议允许 JavaScript 对象定义或定制它们的迭代行为。例如,在 for...of 循环中,哪些值可以被遍历到。以下是迭代协议的两个核心部分:

1. 可迭代协议

要成为可迭代对象,一个对象必须实现 [Symbol.iterator]() 方法。该方法是一个无参函数,返回一个符合迭代器协议的对象。

  • [Symbol.iterator] 的作用
    当一个对象需要被迭代时(例如在 for...of 中),会调用其 [Symbol.iterator]() 方法,返回一个迭代器对象。迭代器对象负责生成迭代的值。

  • 实现方式
    [Symbol.iterator]() 方法可以是普通函数,也可以是生成器函数。生成器函数可以使用 yield 提供每个条目。

2. 迭代器协议

迭代器协议定义了如何生成一系列值。当所有值迭代完毕后,会返回一个默认的结束标志。

  • next() 方法
    一个对象要成为迭代器,必须实现 next() 方法。该方法返回一个对象,包含以下两个属性:
    • done:布尔值,表示是否迭代完成。
    • value:当前迭代的值。

内置可迭代对象

以下是一些内置的可迭代对象:

  • String
  • Array
  • TypedArray
  • Map
  • Set
  • Intl.Segments
  • arguments 对象
  • 一些 DOM 集合类型(如 NodeList

这些对象的原型都实现了 [Symbol.iterator]() 方法。


接受可迭代对象的内置 API

以下内置 API 可以接受可迭代对象:

  • Map
  • WeakMap
  • Set
  • WeakSet
  • Promise.all
  • Promise.allSettled
  • Promise.any
  • Promise.race
  • Array.from
  • Object.groupBy
  • Map.groupBy

示例代码

以下是一些代码示例,帮助理解迭代协议和迭代器协议的实际应用。

1. 自定义可迭代对象
const genObj = {
        [Symbol.iterator]() {
                let i = 0;
                return {
                        next() {
                                i++;
                                if (i === 3) {
                                        return { value: undefined, done: true };
                                }
                                return { value: i, done: false };
                        },
                        return() {
                                console.log('closing');
                                return { done: true };
                        }
                };
        }
};

const [a, b, c] = genObj; // 解构可迭代对象
console.log(a, b, c); // 1 2 undefined

for (const value of genObj) {
        break; // 迭代一次,执行 return 方法
}
2. 使用生成器函数创建迭代器
const myIterator = {
        *[Symbol.iterator]() {
                yield 1;
                yield 2;
                yield 3;
        }
};

console.log([...myIterator]); // [1, 2, 3]
3. 使用类封装可迭代对象
class SimpleClass {
        #data;
        constructor(data) {
                this.#data = data;
        }
        *[Symbol.iterator]() {
                for (const value of this.#data) {
                        yield value;
                }
        }
}

const simple = new SimpleClass([1, 2, 3]);
for (const value of simple) {
        console.log(value); // 1, 2, 3
}
4. 重写字符串的迭代器方法
const str = 'hello';
str[Symbol.iterator] = function () {
        return {
                next() {
                        if (this._first) {
                                this._first = false;
                                return { value: 'bye', done: false };
                        } else {
                                return { done: true };
                        }
                },
                _first: true
        };
};

for (const key of str) {
        console.log(key); // bye
}
5. 简单迭代器实现
function createIterator(items) {
        let i = 0;
        return {
                next() {
                        const done = i >= items.length;
                        const value = !done ? items[i++] : undefined;
                        return { done, value };
                }
        };
}

const iterator = createIterator([1, 2, 3]);
console.log(iterator.next()); // { done: false, value: 1 }
console.log(iterator.next()); // { done: false, value: 2 }
console.log(iterator.next()); // { done: false, value: 3 }

总结

  • 可迭代协议定义了对象如何被迭代,要求实现 [Symbol.iterator]() 方法。
  • 迭代器协议定义了如何生成一系列值,要求实现 next() 方法。
  • JavaScript 提供了许多内置的可迭代对象和支持迭代的 API。
  • 通过生成器函数或自定义类,可以轻松实现自定义的可迭代对象。

理解迭代协议和迭代器协议,不仅有助于掌握 JavaScript 的核心机制,还能帮助我们更高效地处理数据结构和流式数据。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值