JavaScript回顾-迭代器和生成器
处理集合中的每项是常见的操作。JavaScript提供了许多迭代集合的方法,从简单的for
循环到map()
和filter()
。迭代器和生成器将迭代的概念直接带入核心语言,并提供了一种机制来自定义for...of
循环的行为。
迭代器
在 JavaScript 中,迭代器是一个对象,它定义一个序列,并在终止时可能返回一个返回值。更具体地说,迭代器是通过使用 next()
方法实现 Iterator protocol的任何一个对象,该方法返回具有两个属性的对象: value
,这是序列中的 next 值;和 done
,如果已经迭代到序列中的最后一个值,则它为 true
。如果 value
和 done
一起存在,则它是迭代器的返回值。
一旦创建,迭代器对象可以通过重复调用 next()显式地迭代。迭代一个迭代器被称为消耗了这个迭代器,因为它通常只能执行一次。在产生终止值之后,对 next()的额外调用应该继续返回{done:true}。
自定义迭代器:
function makeRangeIterator(start=0,end=100,step=1){
let nextIndex=start;
let iterationCount=0;
const rangeIterator={
next:function (){
let result;
if(nextIndex<end){
result={value:nextIndex,done:false};
nextIndex+=step;
iterationCount++;
return result;
}
return {value:iterationCount,done:true}
}
};
return rangeIterator;
}
//使用此迭代器
let it=makeRangeIterator(1,10,2);
let result =it.next();
while(!result.done){
console.log(result.value);
result=it.next();
}
生成器函数
生成器函数提供一个强大的选择:允许你定义一个包含自有迭代算法的函数,同时它可以自动维护自己的状态。生成器函数使用function*
语法编写。最初调用时,生成器函数不执行任何代码,而是返回一种称为Generator的迭代器。通过调用生成器的下一个方法消耗值时,Generator函数将执行,直到遇到yield关键字。
//生成器函数
function* makeRangeIterator(start=0,end=Infinity,step=1){
for(let i=start;i<end;i+=step){
yield i;
}
}
let a = makeRangeIterator(1,10,2);
a.next() // {value: 1, done: false}
a.next() // {value: 3, done: false}
a.next() // {value: 5, done: false}
a.next() // {value: 7, done: false}
a.next() // {value: 9, done: false}
a.next() // {value: undefined, done: true}
可迭代对象
若一个对象拥有迭代行为,如在for...of
中会循环哪些值,那么那个对象便是一个可迭代对象。一些内置类型,如Array或Map拥有默认的迭代行为,而其他类型没有。
为了实现可迭代,一个对象必须实现@@iterator
方法,这意味着这个对象(或其原型链中的任意一个对象)必须具有一个带Symbol.iterator
键的属性。
自定义可迭代对象:
//自定义可迭代对象
let myIterable={
*[Symbol.iterator](){
yield 1;
yield 2;
yield 3;
}
}
for(let value of myIterable){
console.log(value);
}
// [...myIterable];
内置可迭代对象
String
、Array
、TypedArray
、Map
和Set
都是内置可迭代对象,因为它们的原型对象都拥有一个Symbol.iterator
方法
用于可迭代对象的语法
一些语句和表达式专用于可迭代对象,如例如 for-of
循环,展开语法
,yield*
和 解构赋值
。
for (let value of ['a', 'b', 'c']) {
console.log(value);
}
// "a"
// "b"
// "c"
[...'abc']; // ["a", "b", "c"]
function* gen() {
yield* ['a', 'b', 'c'];
}
gen().next(); // { value: "a", done: false }
[a, b, c] = new Set(['a', 'b', 'c']);
a; // "a"
高级生成器
The next()
方法也接受一个参数用于修改生成器内部状态。传递给 next()
的参数值会被 yield 接收。要注意的是,传给第一个 next()
的值会被忽略。
下面的是斐波那契数列生成器,它使用了 next(x)
来重新启动序列:
function* fibonacci() {
var fn1 = 0;
var fn2 = 1;
while (true) {
var current = fn1;
fn1 = fn2;
fn2 = current + fn1;
var reset = yield current;
if (reset) {
fn1 = 0;
fn2 = 1;
}
}
}
var sequence = fibonacci();
console.log(sequence.next().value); // 0
console.log(sequence.next().value); // 1
console.log(sequence.next().value); // 1
console.log(sequence.next().value); // 2
console.log(sequence.next().value); // 3
console.log(sequence.next().value); // 5
console.log(sequence.next().value); // 8
console.log(sequence.next(true).value); // 0
console.log(sequence.next().value); // 1
console.log(sequence.next().value); // 1
console.log(sequence.next().value); // 2
- 本文链接:https://archer-lan.github.io/2023/11/20/JavaScript%E5%9B%9E%E9%A1%BE-%E8%BF%AD%E4%BB%A3%E5%99%A8%E5%92%8C%E7%94%9F%E6%88%90%E5%99%A8/
- 版权声明:本博客所有文章除特别声明外,均默认采用 许可协议。