Generator函数语法

本文详细介绍了ES6中Generator函数的基础概念、语法特点及其工作原理。重点解释了如何使用yield语句来定义内部状态,next方法的作用及参数传递机制。

基础概念

  • Generator 函数是 ES6 提供的 种异步编程解决方案,语法行为与传统函数完全不同。
  • 执行 Generator 函数会返回 个遍历器对象 也就是说, Generator 函数除了是状态机,还是个遍历器对象生成函数
    返回的遍历器对象可以依次遍历 Generator 函数内部的每 个状态。
  • 形式上, Generator 函数是 个普通函数,但是有三个特征: function 命令与函数名之间有 个星号*: 二是函数体内部使用
    yield 吾句定义不同的内部状态(“ yield ”在英语里的意思就是“产出“);三是使得指针移向下 状态。也就是说, 每次调用
    next 方法,内指针就从函数头部或上 次停下来的地方开始执行 直到遇到下一条yield 语句(或 return 语句)为止 ;换言之
    Generator 函数是分段执行的; yield 语句是暂停执行的标记 ;next 方法可以恢复执行;
function* GeneratorExam() { 
	yield ’hello1’; 
	yield ’hello2’; 
	return ’helloending’; 
}
var suchAs = GeneratorExam() ;

上边代码定义了一个geerator函数 GeneratorExam ,内部有三个状态hello1,hello2,helloending(return语句会结束执行);

suchAs.next(); //{value:'hello1',done:false}

suchAs.next(); //{value:'hello2',done:false}

suchAs.next(); //{value:'helloending',done:true}

suchAs.next(); //{value:undefined,done:true}

上边代码一共调用了四次next()方法

  • 第一次调用, Generator 函数开始执行; 直到遇到第 yield 语句为止 next 方法返回一个对象,它的 value
    属性就是当前 yield 吾句的值 hello1, done 属性的值 false 表示遍历还没有结束。

  • 第二次调用, Generator 函数从上次 yield 语句停下的地方, 一直执行到下 yield语句。next 方法返回的对象的
    value 属性就是当前 yield 语句的值hello2, done 属性false 表示遍历还没有结束。

  • 第三次调用, Generator 函数从上次 yield 语句停下的地方,一直执行到 return 语句( 如果没有 return 语句
    就执行到函数结束); next 方法返回的对象的 value 属性就是紧跟在 return 语句后面的表达式的值(如果没有 return
    吾句 value 属性的值为 undefined) done 属性的值 true 表示遍历己经结束。

  • 第四次调用,此时Generator函数已经运行完毕,next方法返回对象的value值为undefined,done为true,以后再调用这个方法,都是这个值。
    总结一下,调用Generator函数返回一个遍历器对象,代表generator函数的内部指针,以后每次调用遍历器对象的next()方法,就会返回一个有value和done两个属性的对象。value代表当前的内部状态的值,done代表遍历是否结束。

*星号的位置

ES6没有规定function关键字和函数名之间的*星号写在哪个位置,所以以下写法都能通过。

function * such (x , y) { } 
function *such (x, y) {} 
function* such (x, y) { } 
function*such (x, y) {}

next方法的参数

yield 语句本身没有返回值,或者说总是返回 undefined next 方法可以带有 个参数,该参数会被当作上一条 yield 语句的返回值

function* f () {
	for(var i = O; true; i++ ){
		var reset = yield i; 
		if(reset) {i = -1; }
	} 
}
var g = f();

g.next() // { value: 0, done: false }
g.next() // { value: 1, done: false } 
g.next(true) // { value: 0, done : false}
  • 上面的代码先定义了 个可以无限运行的 Generator 函数 ,如果 next 方法没有参数,每 次运行到 yield 吾句时,变量
    reset 的值总是 undefined 。当 next 方法带有一个参数 true 时,当前的变量 reset 就被重置为这个参数(即
    true ),因而 会等于- ,下 轮循环就从- 开始递增。

  • 这个功能有很重要的语法意义 Generator 函数从暂停状态到恢复运行,其上下文状态 (context )是不变的 通过 next
    方法的参数就有办法在 Generator 函数开始运行后继续向函数 体内部注入值 也就是说,可以在
    Generator函数运行的不同阶段从外部向内部注入不同的值, 从而调整函数行为。

再看一个例子

function* foo (x) { 
	var y = 2 * (yield (x + 1)); 
	var z = yield (y / 3) ; 
	return (x + y + z); 
}
var a = foo(5); 
a.next() //{value:6, done:false}
a.next () //{value:NaN, done:false}
a.next () //{value:NaN, done:true}
var b=foo(5);
b.next() //{value:6,done:false}
b.next(12) //{value:8,done:false}
b.next(13) //{value:42,done:true}
  • 上面的代码中,第二次运行 next 方法的时候不带参数,导致 y的值等于 *undefined (即NaN ),除以3 以后还是 NaN
    ,因此返回对象的 value 属性也等于 NaN,第三次运行 Next方法的时候不带参数 所以 等于 undefined ,返回对象的
    value 属性等于 + NaN + undefined, 为NaN。

  • 如果向口next 方法提供参数,返回结果就完全不一样了上面的代码第 次调用b的next 方法时,返回x+1的值6,第二次调用next()方法,将第一次yeild语句值设为12,因此y=24,返回y/3为8; 第三次调用next();将上一次yeild设置为13,因此z为13;x=5;y=24;return为42;

tips

  • 由于next方法的参数表示上一条yield的返回值,因此第一次使用next()方法传参时无效的;V8引擎直接忽略第一次next方法传参;
  • 当然如果想在第一次调用方法就能输入值,可以在Generator函数外面再包一层。
function wrapper(generatorFunction) { 
	return function ( ... args) { 
		let generatorObject = generatorFunction( ... args) ; 
		generatorObject.next() ; 
		return generatorObject;
	};
}

const wrapped= wrapper(function* () { 
	console.log(First put ${yield});
	returnDONE;
}wrapped().next('hello!') //First put hello!

参考:
书籍:《ES6标准入门》;

### 什么是 Generator 函数 Generator 函数是 ES6 中引入的一种特殊类型的函数,它可以返回一个迭代器对象。通过该迭代器对象,可以逐步执行 Generator 函数中的代码并获取其内部的值[^4]。 #### 基本语法 定义一个 Generator 函数时,在 `function` 关键字后面加上星号 (`*`) 表示这是一个 Generator 函数。在函数体中使用 `yield` 关键字暂停和恢复函数的执行,并返回相应的值[^3]。 ```javascript function* myGenerator() { yield 1; yield 2; yield 3; } const generator = myGenerator(); console.log(generator.next().value); // 输出 1 console.log(generator.next().value); // 输出 2 console.log(generator.next().value); // 输出 3 ``` 上述代码展示了如何创建一个简单的 Generator 函数以及如何通过 `.next()` 方法逐步获取生成器返回的值。 --- ### Generator 的工作原理 当调用一个 Generator 函数时,实际上并不会立即执行其中的代码,而是返回一个迭代器对象。每次调用迭代器的 `.next()` 方法时,都会从上一次停止的地方继续执行直到遇到下一个 `yield` 或者到达函数结束位置。 如果 Generator 函数中有多个 `yield` 表达式,则可以通过多次调用 `.next()` 来逐一处理这些表达式的值。 --- ### 复杂场景下的 Generator 使用 #### 调用嵌套的 Generator 函数 默认情况下,直接在一个 Generator 函数中调用另一个 Generator 函数不会自动展开后者的结果。为了实现这一点,需要显式地使用 `yield*` 将子生成器的内容合并到父生成器中[^5]。 ```javascript function* foo() { yield 'aaa'; yield 'bbb'; } function* bar() { yield* foo(); // 展开foo生成器的内容 yield 'ccc'; yield 'ddd'; } let iterator = bar(); for (let value of iterator) { console.log(value); } // aaa bbb ccc ddd ``` 在这里可以看到,`yield*` 提供了一种简洁的方式来组合不同层次的生成逻辑。 --- ### 实现异步操作的同步化表达 利用 Generator 函数配合协程模式(coroutine),能够简化复杂的异步流程管理问题。通常结合第三方库如 co.js 或原生的 async/await 功能来完成这一目标[^1]。 下面是一个基于手动驱动的方式模拟异步请求的例子: ```javascript function wait(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } function* taskScheduler() { console.log('Task started'); yield wait(1000); // 模拟耗时任务 console.log('After first delay'); yield wait(2000); // 又一段延迟 console.log('All tasks completed'); } const schedulerIterator = taskScheduler(); (function exec() { const result = schedulerIterator.next(); if (!result.done) { result.value.then(() => exec()); } })(); ``` 此例子说明了即使面对多阶段延时计算的情况,借助于 Generators 和 Promises 结合也可以让程序看起来像顺序执行那样直观易懂[^1]。 --- ### 总结 - **基本功能**:提供一种机制允许开发者分段运行 JavaScript 程序片段。 - **核心概念**:依靠 `yield/yield*` 控制权转移;依赖 `.next()` 推动进程向前发展。 - **实际用途**:除了作为普通的迭代工具外,还特别适合用来解决复杂状态转换或者协调长时间等待的任务链路等问题。 --- 问题
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值