Iterator(迭代器)是 ES6 引入的一种统一的遍历机制,为各种数据结构提供了统一的访问接口。
迭代器协议#
什么是迭代器#
迭代器是一个对象,它有一个 next() 方法,每次调用返回 { value, done }:
// 手动创建一个迭代器function createIterator(items) { let index = 0
return { next() { if (index < items.length) { return { value: items[index++], done: false } } return { value: undefined, done: true } }, }}
const iterator = createIterator([1, 2, 3])iterator.next() // { value: 1, done: false }iterator.next() // { value: 2, done: false }iterator.next() // { value: 3, done: false }iterator.next() // { value: undefined, done: true }可迭代协议#
可迭代对象需要实现 [Symbol.iterator] 方法,该方法返回一个迭代器:
const iterable = { data: [1, 2, 3],
[Symbol.iterator]() { let index = 0 const data = this.data
return { next() { if (index < data.length) { return { value: data[index++], done: false } } return { done: true } }, } },}
// 现在可以用 for...of 遍历for (const item of iterable) { console.log(item) // 1, 2, 3}
// 也可以用扩展运算符;[...iterable] // [1, 2, 3]内置可迭代对象#
以下内置类型都实现了迭代器协议:
// 数组for (const item of [1, 2, 3]) { console.log(item)}
// 字符串for (const char of 'hello') { console.log(char)}
// Mapfor (const [key, value] of new Map([ ['a', 1], ['b', 2],])) { console.log(key, value)}
// Setfor (const item of new Set([1, 2, 3])) { console.log(item)}
// argumentsfunction test() { for (const arg of arguments) { console.log(arg) }}
// NodeListfor (const node of document.querySelectorAll('div')) { console.log(node)}获取迭代器#
const arr = [1, 2, 3]const iterator = arr[Symbol.iterator]()
iterator.next() // { value: 1, done: false }iterator.next() // { value: 2, done: false }自定义可迭代对象#
范围迭代器#
class Range { constructor(start, end, step = 1) { this.start = start this.end = end this.step = step }
[Symbol.iterator]() { let current = this.start const { end, step } = this
return { next() { if (current <= end) { const value = current current += step return { value, done: false } } return { done: true } }, } }}
const range = new Range(1, 10, 2);[...range] // [1, 3, 5, 7, 9]
for (const n of new Range(1, 5)) { console.log(n) // 1, 2, 3, 4, 5}链表迭代器#
class Node { constructor(value) { this.value = value this.next = null }}
class LinkedList { constructor() { this.head = null this.tail = null }
append(value) { const node = new Node(value) if (!this.head) { this.head = node this.tail = node } else { this.tail.next = node this.tail = node } return this }
*[Symbol.iterator]() { let current = this.head while (current) { yield current.value current = current.next } }}
const list = new LinkedList()list.append(1).append(2).append(3)
;[...list] // [1, 2, 3]树结构迭代器#
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, [new TreeNode(6)]),])
;[...tree] // [1, 2, 4, 5, 3, 6]for…of 循环#
for...of 是消费迭代器的主要方式:
const arr = [1, 2, 3]
// for...of 遍历值for (const item of arr) { console.log(item) // 1, 2, 3}
// for...in 遍历键for (const index in arr) { console.log(index) // '0', '1', '2'}
// for...of 不能直接遍历普通对象const obj = { a: 1, b: 2 }// for (const item of obj) {} // TypeError
// 需要借助 Object.entries 等for (const [key, value] of Object.entries(obj)) { console.log(key, value)}中断迭代#
for (const item of [1, 2, 3, 4, 5]) { if (item === 3) break console.log(item) // 1, 2}
for (const item of [1, 2, 3, 4, 5]) { if (item === 3) continue console.log(item) // 1, 2, 4, 5}return 方法#
迭代器可以定义 return() 方法,在循环提前退出时调用:
function createIterator() { let index = 0 const data = [1, 2, 3, 4, 5]
return { [Symbol.iterator]() { return this },
next() { if (index < data.length) { return { value: data[index++], done: false } } return { done: true } },
return() { console.log('Iterator closed') return { done: true } }, }}
const iterator = createIterator()
for (const item of iterator) { console.log(item) if (item === 2) break}// 1// 2// Iterator closed使用迭代器的场景#
扩展运算符#
const arr = [...'hello'] // ['h', 'e', 'l', 'l', 'o']const set = new Set([...'hello']) // Set {'h', 'e', 'l', 'o'}解构赋值#
const [a, b, c] = new Set([1, 2, 3])console.log(a, b, c) // 1 2 3
const [first, ...rest] = 'hello'console.log(first) // 'h'console.log(rest) // ['e', 'l', 'l', 'o']Array.from#
const map = new Map([ ['a', 1], ['b', 2],])Array.from(map) // [['a', 1], ['b', 2]]Array.from(map.keys()) // ['a', 'b']Array.from(map.values()) // [1, 2]Promise.all 等#
const promises = new Set([ Promise.resolve(1), Promise.resolve(2), Promise.resolve(3),])
Promise.all(promises).then(console.log) // [1, 2, 3]实用工具函数#
创建范围#
function* range(start, end, step = 1) { for (let i = start; i <= end; i += step) { yield i }}
;[...range(1, 5)] // [1, 2, 3, 4, 5];[...range(0, 10, 2)] // [0, 2, 4, 6, 8, 10]无限序列#
function* naturals() { let n = 1 while (true) { yield n++ }}
function take(iterable, n) { const result = [] for (const item of iterable) { if (result.length >= n) break result.push(item) } return result}
take(naturals(), 5) // [1, 2, 3, 4, 5]迭代器工具#
// mapfunction* map(iterable, fn) { for (const item of iterable) { yield fn(item) }}
// filterfunction* filter(iterable, predicate) { for (const item of iterable) { if (predicate(item)) { yield item } }}
// takefunction* take(iterable, n) { let count = 0 for (const item of iterable) { if (count++ >= n) break yield item }}
// 组合使用const result = [ ...take( filter( map([1, 2, 3, 4, 5], (x) => x * 2), (x) => x > 4 ), 2 ),]// [6, 8]小结#
| 概念 | 说明 |
|---|---|
| 迭代器 | 有 next() 方法的对象 |
| 可迭代对象 | 有 [Symbol.iterator] 方法的对象 |
| for…of | 遍历可迭代对象的值 |
| 使用场景 | 扩展运算符、解构、Array.from 等 |
迭代器协议为 JavaScript 提供了统一的遍历接口,是 Generator、for…of、扩展运算符等特性的基础。