生成器 (Generator)
什么是生成器呢,其实生成器 跟迭代器的逻辑一样,迭代器是依次获取数据每次只返回一个,生成器也是每次只能返回一次结果,下次再次调用返回下一个结果,两个都不会返回之前重复。接下来我们去看如何创建一个生成器
function* method(){
}
这个就是一个生成器。 是不是很那个啥,没啥特别的,就比正常函数多了个*,生成器的创建,必须使用生成器函数(Generator Function)
const g = function* () {
console.log("第1次运行")
yield 1;
console.log("第2次运行")
yield 2;
console.log("第3次运行")
}
const gen = g();
我们从MDN上,我们可以知道,生成器他是遵循可迭代协议和迭代器协议的
Generator.prototype.next()
var g = function* () {
console.log("第1次运行")
yield 1;
console.log("第2次运行")
yield 2;
console.log("第3次运行")
}
const gen1 = g();
const gen2 = g;
console.log(gen1) // 打印是什么
console.log(gen2) // 打印是什么
// Object [Generator] {}
// [GeneratorFunction: g]
在 JavaScript 中,使用 function* 关键字定义的函数为生成器函数,它会返回一个迭代器对象。迭代器对象可以通过调用 .next() 方法来一次一次地迭代返回生成器函数中使用 yield 关键字生成的值。
因此,要使用一个生成器函数,我们需要先创建一个迭代器对象,然后再通过迭代器对象来获取生成器函数生成的值。
在你提供的代码中,const gen = generator() 中的 generator() 实际上是调用了生成器函数,并返回一个迭代器对象。所以这里我们需要通过 () 来调用 generator() 函数,并将返回的迭代器对象赋值给 gen 变量。
如果我们将代码修改为 const gen = generator,则实际上 gen 变量会存储的是 generator 函数本身,而不是通过 generator() 函数调用返回的迭代器对象。当我们对 gen 变量调用 .next() 方法时,会报错,因为 gen 并不是迭代器对象。
因此,正确的做法是需要使用 () 调用生成器函数,获取生成器函数返回的迭代器对象,才能正确地使用生成器函数生成的值。
var g = function* () {
console.log("第1次运行")
yield 1;
console.log("第2次运行")
yield 2;
console.log("第3次运行")
}
const gen = g();
console.log(gen.next())
console.log(gen.next())
console.log(gen.next())
console.log(gen.next())
Generator.prototype.return()
return方法:调用该方法,可以提前结束生成器函数,从而提前让整个迭代过程结束
var g = function* () {
console.log("第1次运行")
yield 1;
console.log("第2次运行")
yield 2;
console.log("第3次运行")
}
const gen = g();
console.log(gen.next())
console.log(gen.return()) // 打印什么 后续打印什么
console.log(gen.next())
console.log(gen.next())
如果上面换成
console.log(gen.next())
console.log(gen.return(4)) // 打印什么 后续打印什么
console.log(gen.next())
console.log(gen.next())
Generator.prototype.return() 方法是 Generator 对象的一个方法,用于中止-generator-迭代器,以及返回一个包含给定值的对象,该对象表示生成器返回的最终值。它的使用场景通常是可以提前终止生成器的执行,因为它会在终止执行后,立即返回一个包含给定值的对象。
当我们调用 generator.return(value) 时,实际上会返回一个 { value, done: true } 的对象,其中 value 是传递给 return() 方法的参数,done 值为 true 表示迭代器已经结束。此时,迭代器就不会再执行下去了,而是直接结束,并返回一个包含给定值的对象作为最终结果。
需要注意的是,如果在调用 return() 方法之前,生成器函数内部已经完成了所有的迭代操作并返回了一个值,则 return() 方法不会生效。换句话说,如果 return() 方法发挥作用了,那么返回值是 return() 方法所传入的值,而不是生成器函数内部返回的值。
简单来说,Generator.prototype.return() 的原理就是通过给定的值来终止生成器函数的执行,并且在终止执行后,返回一个包含给定值的对象作为最终结果。
Generator.prototype.throw()
调用该方法,可以在生成器中产生一个错误
var g = function* () {
try {
console.log("第1次运行")
yield 1;
console.log("第2次运行")
yield 2;
console.log("第3次运行")
} catch(error) {
console.error('出现了错误:', error);
}
}
const gen = g();
console.log(gen.next())
console.log(gen.throw(4))
console.log(gen.next())
console.log(gen.next())
// 要上面换成
console.log(gen.next())
console.log(gen.next())
console.log(gen.next())
console.log(gen.throw(4))
Generator.prototype.throw() 方法是 Generator 对象的一个方法,用于向-generator-迭代器抛出一个异常,并且暂停-generator-迭代器的执行。它的使用场景通常是可以在-generator-函数内部捕获这个异常,并根据具体情况进行处理。
当我们调用 generator.throw(error) 时,实际上会抛出一个指定的异常,并将控制权交还给生成器函数,让它能够进行异常的捕获和处理。如果生成器函数能够捕获并处理抛出的异常,则会继续执行生成器函数后面的语句。如果无法捕获或处理,则会直接向上层抛出异常,导致程序崩溃。
需要注意的是,当我们使用 generator.throw() 抛出异常时,如果当前位置有 try...catch 语句进行了异常的捕获与处理,那么就会执行相应的 catch 块中的代码。如果没有 try...catch 语句进行处理,则会一直向上层查找,直到有相应的 catch 块为止。
简单来说,Generator.prototype.throw() 的原理就是向-generator-迭代器抛出一个异常,并且暂停-generator-迭代器的执行,让生成器函数内部可以捕获和处理这个异常,从而达到控制程序流程和错误处理的目的。