迭代、迭代器、生成器的前世今生

365bet体育在线主页 📅 2026-07-27 11:41:38 ✍️ admin 👁️ 4918 ❤️ 383
迭代、迭代器、生成器的前世今生

什么是迭代

类似于遍历 遍历:有多个数据组成的集合数据结构(map、set、array等其他类数组),需要从该结构中依次取出数据进行某种处理。 迭代:按照某种逻辑,依次取出下一个数据进行处理。

什么是迭代器 iterator

JS语言规定,如果一个对象具有next方法,并且next方法满足一定的约束,则该对象是一个迭代器(iterator)。 next方法的约束:该方法必须返回一个对象,该对象至少具有两个属性:

value:any类型,下一个数据的值,如果done属性为true,通常,会将value设置为undefined

done:bool类型,是否已经迭代完成

通过迭代器的next方法,可以依次取出数据,并可以根据返回的done属性,判定是否迭代结束。

案例如下:

/**

* 迭代器

* 必须有个next函数

* 该函数必须返回一个对象 包括 value 属性 和 done属性

* value:本次迭代的返回值

* done:true 或者 false 本次迭代是否结束

* */

const iterator = {

total:3,

index:1,

next(){

const obj = {

value:this.index > this.total?undefined:Math.random(),

done:this.index > this.total

}

this.index++;

return obj;

}

}

//一个一个迭代直到不能迭代为止

let result = iterator.next();

while(!result.done){

console.log(result);

result = iterator.next();

}

//输出斐波拉数列的数据

//1 1 2 3 5 8 13 21

const sequenceItereator = {

a:1,

b:1,

curIndex:1, //当前从1开始算

next(){

if(this.curIndex == 1 || this.curIndex == 2){

this.curIndex++;

return {

value:1,

done:false

}

}

var c = this.a + this.b;

this.curIndex++;

this.a = this.b;

this.b = c;

return {

value:c,

done:false

}

}

}

for(var i = 0;i<50;i++){

console.log(sequenceItereator.next());

}

什么是迭代器创建函数

它是指一个函数,调用该函数后,返回一个迭代器,则该函数称之为迭代器创建函数,可以简称位迭代器函数。

案例如下:

//迭代器创建函数

function createIterator(arr){

var i = 0;

return {

next(){

var obj = {

value:arr[i],

done:i>arr.length - 1

}

i++;

return obj;

}

}

}

var iterator = createIterator([1,3,5,7,9]);

console.log(iterator);

什么是可迭代协议

ES6中出现了for-of循环,该循环就是用于迭代某个对象的,因此,for-of循环要求对象必须是可迭代的(对象必须满足可迭代协议) 可迭代协议是用于约束一个对象的,如果一个对象满足下面的规范,则该对象满足可迭代协议,也称之为该对象是可以被迭代的。 可迭代协议的约束如下:

对象必须有一个知名符号属性(Symbol.iterator)

done:bool类型,是否已经迭代完成

该属性必须是一个无参的迭代器创建函数

案例如下:

//可迭代协议

var robj = {

[Symbol.iterator]:function(){

var total = 3;

var i = 1;

return {

next(){

var oop = {

value:i>total?undefined:Math.random(),

done:i>total

}

i++;

return oop;

}

}

}

};

for (const element of robj) {

console.log(element);

}

什么是生成器

生成器:由构造函数Generator创建的对象,该对象既是一个迭代器,同时,又是一个可迭代对象(满足可迭代协议的对象)

**注意:Generator构造函数,不提供给开发者使用,仅作为JS引擎内部使用**

生成器函数(生成器创建函数):该函数用于创建一个生成器。

ES6新增了一个特殊的函数,叫做生成器函数,只要在函数名与function关键字之间加上一个*号,则该函数会自动返回一个生成器

生成器函数的特点:

调用生成器函数,会返回一个生成器,而不是执行函数体(因为,生成器函数的函数体执行,收到生成器控制)

每当调用了生成器的next方法,生成器的函数体会从上一次yield的位置(或开始位置)运行到下一个yield

yield关键字只能在生成器内部使用,不可以在普通函数内部使用

它表示暂停,并返回一个当前迭代的数据

如果没有下一个yield,到了函数结束,则生成器的next方法得到的结果中的done为true

yield关键字后面的表达式返回的数据,会作为当前迭代的数据

生成器函数的返回值会作最终的value的值 但是当在进行next时 value是undefined

生成器在调用next的时候可以传递参数,该参数会作为上一次yield整个表达式的返回结果

案列如下:

//生成器函数 调用该函数返回一个生成器 该生成器即使是一个迭代器 又是一个可迭代对象(满足可迭代协议)

function* createGenerator(){

console.log('函数体执行 - 开始');

yield 1; //会作为本次迭代的value值 {value:1,done:false}

console.log("函数体执行 - 1")

yield 2;//会作为本次迭代的value值 {value:2,done:false}

console.log('函数体执行 - 2');

yield 3;//会作为本次迭代的value值 {value:3,done:false}

console.log("函数体执行 - 3");

return "结束"//会作为本次迭代的value值 {value:"结束",done:true}

}

//掉用只会返回一个生成器 不会执行函数体

var generator = createGenerator();

//当调用next的时候会从开始位置到第一个yield处执行 执行到yield位置就会卡住(不会继续执行), 等到下一次next的时候

//生成器的函数体会从上一次yield的位置(或开始位置)运行到下一个yield

console.log(generator.next);

const iterator = generator[Symbol.iterator]();

function* createArrayIterator(array){

for (let index = 0; index < array.length; index++) {

const item = array[index];

console.log(`第${index}次迭代`);

yield item;

}

}

const arrayIterator = createArrayIterator([1,2,3,4,5,6]);

//生成器函数 调用该函数返回一个生成器 该生成器即使是一个迭代器 又是一个可迭代对象(满足可迭代协议)

function* createGenerator(){

console.log('函数体执行 - 开始');

let result = yield 1; //会作为本次迭代的value值 {value:1,done:false}

console.log("函数体执行 - 1",result)

result = yield 2;//会作为本次迭代的value值 {value:2,done:false}

console.log('函数体执行 - 2',result);

result = yield 3;//会作为本次迭代的value值 {value:3,done:false}

console.log("函数体执行 - 3",result);

return "结束"//会作为本次迭代的value值 {value:"结束",done:true}

}

let itereator = createGenerator();

let res = itereator.next();

function run(){

if(!res.done){

//如果在调用next的时候 给 next传递参数 该参数会作为 yield 整个表达式的值返回

//执行步骤

//第一次调用就不care了 第一次调用碰到yield 1; 就会卡住不会往下执行 这个时候还不执行赋值操作

//第二次调用next 传递上一次迭代的值作为参数传递 这个时候 就会从上一次 yield的位置 运行到下一个yield (这个时候就会进行赋值操作)

//整个yield 表达式的返回值 就是给next函数传递的参数

//依次类推

console.log(res);

res = itereator.next("张三:"+Math.random());

run();

}

}

run();

var i = 0;

function asyncData(){

return new Promise((resolve,reject)=>{

setTimeout(() => {

i++;

//3秒后完成 完成的数据

resolve('完成'+i);

}, 10000);

})

}

//调用next()方法时传入的值会作为上一个yield表达式的返回值

//创建一个生成器函数 调用时返回一个生成器

function* task(){

console.log("开始获取数据");

let data = yield asyncData();

console.log('获取到的数据',data);

data = yield asyncData();

console.log("又获取到了数据",data);

data = yield 1;

console.log('又获取到了数据',data);

return '结束';

}

//没封装之前的写法

/*function run(createGenerator){

const generator = createGenerator();

let res = generator.next();

function next(){

if(!res.done){

console.log(res);

const value = res.value;

if(typeof value.then === 'function'){

value.then((data)=>{

res = generator.next(data);

next();

});

}else{

res = generator.next(value);

next();

}

}

}

next();

}*/

//封装后的写法

function run(createGenerator){

const generator = createGenerator();

console.log(generator);

next();

function next(nextValue){

const res = generator.next(nextValue);

if(res.done){

console.log('生成器迭代结束');

return;

}

const value = res.value;

if(typeof value.then === 'function'){

//如果返回的是promise 将promise完成时的数据作为参数

//作为上一次yield表达式的返回值

value.then((data)=>{

return next(data)

})

}else{

console.log('走这里了')

//将上一次迭代获取到的value的值作为参数 传递给上一次yield表达式的返回值

next(res.value);

}

}

}

run(task);

function* g2(){

console.log('g2函数体-运行');

let res = yield 'g1';

console.log('g1运行');

res = yield 'g2';

console.log('g2运行')

return 123;

}

function* createGenerator(){

console.log('函数体-开始')

let res = yield 1; //1作为 本次迭代的值 {value:1,done:false}

console.log('函数体-运行1',res);

res = yield* g2();

console.log('函数体-g2',res);

res = yield 2;

console.log('函数体-运行2',res);

res = yield 3;

console.log('函数体-运行3',res);

return '结束'

}

var generator = createGenerator();

总结:

生成器的核心价值在于其‌延迟执行与状态保持能力‌,适用于:

需要按需生成数据的迭代场景(如分页、树遍历)

资源敏感型任务(如大文件处理、流式传输)

复杂流程控制(如多步骤交互、状态机)

尽管 async/await 更常用于异步编程,但生成器在定制化迭代器协议、性能优化框架中仍不可替代

相关推荐

虞美人·春花秋月何时了
365bet怎么注册

虞美人·春花秋月何时了

📅 01-20 👁️ 7870
暴雪战网Battle.net将统一更名为Blizzard
365bet体育在线主页

暴雪战网Battle.net将统一更名为Blizzard

📅 08-31 👁️ 1697
什么是 RESTful API?从日常生活理解 REST 架构原理
365bet怎么注册

什么是 RESTful API?从日常生活理解 REST 架构原理

📅 01-10 👁️ 5098