迭代器是 JavaScript 中很常见且十分有用的一种设计模式,它可以通过迭代器接口依次访问某种集合中的所有元素。ES7 引入了 Iterator 和 Generator 两个概念,它们可以非常方便地实现迭代器模式,并且使得代码更加清晰、易读。本文将介绍详细的 Iterator 和 Generator 迭代器的概念和用法,希望能给大家带来帮助。
Iterator 迭代器
Iterator 迭代器是一种机制,它可以让用户定义自己的迭代方式,遍历集合中每一个元素。目前,JavaScript 内置支持迭代器的数据类型有 Array、Map、Set、String 和 TypedArray 等。Iterator 迭代器的本质是通过一个 next
方法,控制遍历的过程,同时返回遍历过程中每一个元素的值。迭代器的接口规范为:
interface IteratorResult { done: boolean; value: any; } interface Iterator { next(): IteratorResult; }
其中,done
属性用于判断遍历是否结束,value
属性表示当前取出的值。下面是一个简单的例子,用于演示如何使用迭代器来遍历数组:
let arr = [1, 2, 3]; let iter = arr[Symbol.iterator](); // 通过 Symbol.iterator 得到迭代器 console.log(iter.next()); // { done: false, value: 1 } console.log(iter.next()); // { done: false, value: 2 } console.log(iter.next()); // { done: false, value: 3 } console.log(iter.next()); // { done: true, value: undefined }
可以看到,迭代器的 next
方法返回的是一个迭代结果对象,其中 done
表示遍历是否结束,value
表示当前取出的值。如果迭代结束,则返回的结果对象中 done
属性为 true
,value
为 undefined
。
使用 for...of
语句,可以方便地使用迭代器遍历集合:
let arr = [1, 2, 3]; for (let v of arr) { console.log(v); // 1, 2, 3 }
由于数组继承自 Array.prototype,而 Array.prototype 本身就实现了迭代器接口,所以上面的代码可以通过数组的迭代器实现。同样,Map、Set、String 等数据类型也都支持迭代器接口。
用户也可以自己定义自己的数据类型实现迭代器接口,从而可以使用迭代器来遍历数据类型。下面是一个示例代码,定义了一个自己的迭代器:
class RangeIterable { constructor(start, end) { this.start = start; this.end = end; } [Symbol.iterator]() { let currentValue = this.start; let self = this; return { next() { if (currentValue <= self.end) { return { done: false, value: currentValue++ }; } else { return { done: true, value: undefined }; } } } } }
这个 RangeIterable
类的实例可以用于生成一段连续的整数序列。它通过重载 Symbol.iterator
方法,返回一个可以遍历整数序列的迭代器。
let iterable = new RangeIterable(1, 5); for (let i of iterable) { console.log(i); // 1, 2, 3, 4, 5 }
Generator 迭代器
Generator 迭代器是 ES6 中引入的一种新的函数类型,它可以看作是一个状态机,可以在执行过程中暂停和恢复执行。在更加底层的层面上,每次调用 Generator 函数时,都会返回一个新的 Iterator 迭代器对象。
使用 Generator 迭代器的语法,需要使用 function*
关键字声明一个 Generator 函数。Generator 函数内部使用 yield
关键字可以控制函数的执行过程:
function* myGenerator() { yield 1; yield 2; yield 3; return 4; } let iter = myGenerator(); console.log(iter.next()); // { done: false, value: 1 } console.log(iter.next()); // { done: false, value: 2 } console.log(iter.next()); // { done: false, value: 3 } console.log(iter.next()); // { done: true, value: 4 }
在 Generator 函数内部,我们可以使用 yield
关键字来暂停函数的执行过程,以便用户可以通过 next
方法来控制函数的执行过程。同时我们还可以在 Generator 函数内部使用 return
语句来终止迭代器的遍历。
Generator 迭代器的最大的优点在于,它可以非常便捷地实现从异步操作中返回数据。通过使用 yield
关键字,我们可以将异步操作转换为同步操作。下面是一个简单的例子,用于演示如何使用 Generator 迭代器来实现异步操作:
function asyncFun() { setTimeout(() => generator.next('hello'), 1000); } function* myGenerator() { const result = yield asyncFun(); console.log(result); // hello } let generator = myGenerator(); generator.next();
用于实现异步操作的 asyncFun
函数,利用了 setTimeout
函数,延迟了执行时间。而 myGenerator
函数中使用了 yield
关键字来暂停函数的执行过程。在异步操作完成后,再次调用 generator.next
方法,继续执行函数。
总结
Iterator 和 Generator 迭代器是 JavaScript 中非常有用的机制,它们可以方便地实现迭代器模式,帮助我们遍历集合中的元素。同时,对于异步操作等情况,使用 Generator 迭代器可以实现非常完美的效果。希望本文能够给大家带来帮助。
参考资料
来源:JavaScript中文网 ,转载请注明来源 本文地址:https://www.javascriptcn.com/post/659e2a42add4f0e0ff73abdc