迭代器对象
迭代器协议
ECMAScript 6 引入了迭代器协议,定义了标准的方式来产生一系列值。任何对象只要实现了迭代器协议,就可以成为迭代器对象。迭代器协议要求对象必须实现一个 next()
方法,该方法返回一个包含 value
和 done
属性的对象。
const simpleIterator = {
data: [1, 2, 3],
index: 0,
next() {
return this.index < this.data.length
? { value: this.data[this.index++], done: false }
: { value: undefined, done: true };
}
};
console.log(simpleIterator.next()); // { value: 1, done: false }
console.log(simpleIterator.next()); // { value: 2, done: false }
console.log(simpleIterator.next()); // { value: 3, done: false }
console.log(simpleIterator.next()); // { value: undefined, done: true }
可迭代协议
可迭代协议允许 JavaScript 对象定义或定制它们的迭代行为。要成为可迭代对象,必须实现 @@iterator
方法,即对象或其原型链上必须有一个键为 Symbol.iterator
的属性。
const iterableObject = {
items: ['a', 'b', 'c'],
[Symbol.iterator]() {
let index = 0;
return {
next: () => {
return index < this.items.length
? { value: this.items[index++], done: false }
: { value: undefined, done: true };
}
};
}
};
for (const item of iterableObject) {
console.log(item); // 依次输出 'a', 'b', 'c'
}
内置可迭代对象
ES6 中许多内置对象默认就是可迭代的,包括:
- Array
- String
- Map
- Set
- TypedArray
- arguments 对象
- DOM NodeList
// 数组迭代
const arr = [10, 20, 30];
for (const num of arr) {
console.log(num);
}
// 字符串迭代
const str = 'hello';
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);
}
生成器函数与迭代器
生成器函数是创建迭代器的更简洁方式。使用 function*
语法定义的函数返回一个生成器对象,该对象符合可迭代协议和迭代器协议。
function* numberGenerator() {
yield 1;
yield 2;
yield 3;
}
const gen = numberGenerator();
console.log(gen.next()); // { value: 1, done: false }
console.log(gen.next()); // { value: 2, done: false }
console.log(gen.next()); // { value: 3, done: false }
console.log(gen.next()); // { value: undefined, done: true }
// 也可以直接用于迭代
for (const num of numberGenerator()) {
console.log(num); // 依次输出 1, 2, 3
}
迭代器的高级用法
自定义迭代逻辑
可以创建复杂的迭代逻辑,比如实现一个斐波那契数列迭代器:
const fibonacci = {
[Symbol.iterator]() {
let prev = 0, curr = 1;
return {
next() {
[prev, curr] = [curr, prev + curr];
return { value: prev, done: false };
}
};
}
};
// 获取前10个斐波那契数
let count = 0;
for (const num of fibonacci) {
console.log(num);
if (++count >= 10) break;
}
组合迭代器
可以通过组合多个迭代器来创建更复杂的迭代行为:
function* chain(...iterables) {
for (const iterable of iterables) {
yield* iterable;
}
}
const combined = chain([1, 2], new Set([3, 4]), '56');
console.log([...combined]); // [1, 2, 3, 4, '5', '6']
迭代器与解构赋值
迭代器可以与解构赋值结合使用:
const [first, second] = [10, 20, 30];
console.log(first, second); // 10 20
const [head, ...tail] = 'hello';
console.log(head, tail); // 'h', ['e', 'l', 'l', 'o']
异步迭代器
ES2018 引入了异步迭代器,用于处理异步数据流。异步迭代器返回 Promise 对象:
const asyncIterable = {
[Symbol.asyncIterator]() {
let i = 0;
return {
next() {
if (i < 3) {
return Promise.resolve({ value: i++, done: false });
}
return Promise.resolve({ done: true });
}
};
}
};
(async function() {
for await (const num of asyncIterable) {
console.log(num); // 依次输出 0, 1, 2
}
})();
迭代器辅助方法
可以创建各种辅助方法来操作迭代器:
function take(iterable, count) {
const iterator = iterable[Symbol.iterator]();
return {
[Symbol.iterator]() {
return this;
},
next() {
if (count-- <= 0) return { done: true };
return iterator.next();
}
};
}
const numbers = [1, 2, 3, 4, 5];
console.log([...take(numbers, 3)]); // [1, 2, 3]
迭代器性能考虑
使用迭代器时需要注意性能问题。与直接数组访问相比,迭代器会产生额外的开销:
// 直接访问
const arr = [...Array(1000000).keys()];
console.time('direct');
let sum = 0;
for (let i = 0; i < arr.length; i++) {
sum += arr[i];
}
console.timeEnd('direct');
// 使用迭代器
console.time('iterator');
sum = 0;
for (const num of arr) {
sum += num;
}
console.timeEnd('iterator');
迭代器与生成器的错误处理
迭代器和生成器可以处理错误情况:
function* withErrorHandling() {
try {
yield 1;
throw new Error('Something went wrong');
yield 2;
} catch (e) {
yield 'Caught: ' + e.message;
}
}
const gen = withErrorHandling();
console.log(gen.next()); // { value: 1, done: false }
console.log(gen.next()); // { value: 'Caught: Something went wrong', done: false }
console.log(gen.next()); // { value: undefined, done: true }
迭代器与状态管理
迭代器可以用于状态管理,保持内部状态:
function createCounter(start = 0, step = 1) {
return {
[Symbol.iterator]() {
return this;
},
next() {
const value = start;
start += step;
return { value, done: false };
}
};
}
const counter = createCounter(5, 2);
console.log(counter.next().value); // 5
console.log(counter.next().value); // 7
console.log(counter.next().value); // 9
迭代器与无限序列
迭代器特别适合表示无限序列:
function* naturalNumbers() {
let n = 0;
while (true) {
yield n++;
}
}
const numbers = naturalNumbers();
console.log(numbers.next().value); // 0
console.log(numbers.next().value); // 1
console.log(numbers.next().value); // 2
// 可以无限继续下去
迭代器与树结构遍历
迭代器可以用于实现复杂的树结构遍历:
class TreeNode {
constructor(value, children = []) {
this.value = value;
this.children = children;
}
*[Symbol.iterator]() {
yield this.value;
for (const child of this.children) {
yield* child;
}
}
}
const tree = new TreeNode(1, [
new TreeNode(2, [
new TreeNode(4),
new TreeNode(5)
]),
new TreeNode(3)
]);
console.log([...tree]); // [1, 2, 4, 5, 3]
本站部分内容来自互联网,一切版权均归源网站或源作者所有。
如果侵犯了你的权益,请来信告知我们删除。邮箱:cc@cccx.cn
上一篇:可迭代对象
下一篇:for...of循环原理