概述
Generator生成器详解
- generator函数
- 定义
- 迭代器对象的方法
- next方法
- throw方法
- return方法
- next、throw、return共同点
- yield*表达式
- Generator 函数的this
- generator函数应用
- 状态机
- 部署iterator接口
- 异步操作的同步化表达
- 流程控制
- 注意点
- 注意点一
- 注意点二
- 注意点三
- 注意点四
generator函数
定义
定义:
1、function关键字和函数名之间加上*号
2、函数内部使用yield表达式来暂停函数执行,并将表达式的值返回
function* f(){
yield 'hello ';
yield 'javascript';
return "test";
}
var obj = f() //生成器函数执行后返回一个迭代器对象,内部代码不会立即执行
obj.next() // {value: "hello ", done: false}
obj.next() // {value: "javascript", done: false}
obj.next() // {value: "test", done: true}
执行流程: 调用 Generator 函数,返回一个遍历器对象,代表 Generator 函数的内部指针。以后,每次调用遍历器对象的next方法,就会返回一个有着value和done两个属性的对象。value属性表示当前的内部状态的值,是yield表达式后面那个表达式的值;done属性是一个布尔值,表示是否遍历结束
迭代器对象的方法
next方法
next方法的逻辑:
(1)遇到yield表达式,就暂停执行后面的操作,并将紧跟在yield后面的那个表达式的值,作为返回的对象的value属性值。
(2)下一次调用next方法时,再继续往下执行,直到遇到下一个yield表达式。
(3)如果没有再遇到新的yield表达式,就一直运行到函数结束,直到return语句为止,并将return语句后面的表达式的值,作为返回的对象的value属性值。
(4)如果该函数没有return语句,则返回的对象的value属性值为undefined。
next方法的参数:
yield表达式本身没有返回值,或者说总是返回undefined。next方法可以带一个参数,该参数就会被当作上一个yield表达式的返回值。
function* f(){
console.log(3 + (yield));
}
var g = f()
g.next();
//g.next(); //打印NaN
g.next(7); //打印7
throw方法
enerator 函数返回的遍历器对象,都有一个throw方法, 用于在当前的yield处抛出异常,可以接收一个参数当做抛出的异常。如果内部不捕获,则向外抛出
function* f() {
try {
yield;
} catch (e) {
console.log('内部捕获', e);
}
};
var iter = f();
iter .next();
try {
iter.throw('a');
iter.throw('b');
} catch (e) {
console.log('外部捕获', e);
}
// 内部捕获 a
// 外部捕获 b
return方法
Generator 函数返回的遍历器对象,还有一个return()方法,可以返回给定的值,并且终结遍历 Generator 函数。
function* f() {
yield 1;
yield 2;
yield 3;
}
var gen = f();
gen.next()
// { value: 1, done: false }
gen.return('foo') // { value: "foo", done: true }
gen next()
// { value: undefined, done: true }
next、throw、return共同点
next()、throw()、return()这三个方法的作用都是让 Generator 函数恢复执行,并且使用不同的语句替换yield表达式。
next()是将yield表达式替换成一个值。
const g = function* (x, y) {
let result = yield x + y;
return result;
};
const gen = g(1, 2);
gen.next(); // Object {value: 3, done: false}
gen.next(1); // Object {value: 1, done: true}
// 相当于将 let result = yield x + y
// 替换成 let result = 1;
throw()是将yield表达式替换成一个throw语句。
gen.throw(new Error('出错了')); // Uncaught Error: 出错了
// 相当于将 let result = yield x + y
// 替换成 let result = throw(new Error('出错了'));
return()是将yield表达式替换成一个return语句。
gen.return(2); // Object {value: 2, done: true}
// 相当于将 let result = yield x + y
// 替换成 let result = return 2;
yield*表达式
yield*后面接iterable对象, 默认会调用它的迭代器方法,用于遍历对象。
例子一
function* foo() {
yield 'a';
yield 'b';
}
function* bar() {
yield 'x';
yield* foo();
yield 'y';
}
// 等同于
function* bar() {
yield 'x';
for (let v of foo()) {
yield v;
}
yield 'y';
}
for (let v of bar()){
console.log(v);
}
// "x"
// "a"
// "b"
// "y"
例子二
function* foo() {
yield 2;
yield 3;
return "foo"; //作为yield*表达式的返回值
}
function* bar() {
yield 1;
var v = yield* foo(); // v="foo"
console.log("v: " + v);
yield 4;
}
var it = bar();
it.next()
// {value: 1, done: false}
it.next()
// {value: 2, done: false}
it.next()
// {value: 3, done: false}
it.next();
// "v: foo"
// {value: 4, done: false}
it.next()
// {value: undefined, done: true}
Generator 函数的this
Generator 函数总是返回一个迭代器,ES6 规定这个迭代器是 Generator 函数的实例,也继承了 Generator 函数的prototype对象上的方法
function* f(){}
f.prototype.hello = function(){
console.log('hello');
}
var gen = f();
gen instanceof f // true
gen.hello() // hello
f函数内部的this不是指向该迭代器对象。
function* f() {
this.a = 11;
}
let gen = f();
gen.next();
gen.a // undefined
Generator 函数也不能跟new命令一起用,会报错。
function* F() {
yield this.x = 2;
yield this.y = 3;
}
new F() // TypeError: F is not a constructor
generator函数应用
状态机
//es5状态机的实现
var ticking = true;
var clock = function() {
if (ticking)
console.log('Tick!');
else
console.log('Tock!');
ticking = !ticking;
}
//es6状态机的实现
var clock = function* () {
while(true){
console.log('Tick!');
yield;
console.log('Tock!');
yield;
}
}
部署iterator接口
var myIterable = {};
myIterable[Symbol.iterator] = function* () {
yield 1;
yield 2;
yield 3;
};
[...myIterable] //[1、2、3]
异步操作的同步化表达
function* main() {
var result = yield request("http://www.baidu.com");
var resp = JSON.parse(result);
console.log(resp.value);
}
function request(url) {
makeAjaxCall(url, function(response){
it.next(response);
});
}
function makeAjaxCall(url, callbackfn){
var xhr = new XMLHttpRequest();
xhr.open('GET', url, true);
xhr.onreadystatechange = function(){
if(xhr.readyState === 4){
callbackfn(xhr.responseText);
}
}
xhr.send();
}
var it = main();
it.next();
流程控制
如果有一个多步操作非常耗时,采用回调函数,可能会写成下面这样。
step1(function (value1) {
step2(value1, function(value2) {
step3(value2, function(value3) {
step4(value3, function(value4) {
// Do something with value4
});
});
});
});
采用 Promise 改写上面的代码。
Promise.resolve(step1)
.then(step2)
.then(step3)
.then(step4)
.then(function (value4) {
// Do something with value4
}, function (error) {
// Handle any error from step1 through step4
})
Generator 函数可以进一步改善代码运行流程。
function* longRunningTask(value1) {
try {
var value2 = yield step1(value1);
var value3 = yield step2(value2);
var value4 = yield step3(value3);
var value5 = yield step4(value4);
// Do something with value4
} catch (e) {
// Handle any error from step1 through step4
}
}
注意点
注意点一
yield表达式只能出现在generator函数中
function f(){
yield; //error,只能出现在generator函数中
}
注意点二
yield表达式如果在另一个表达式中,需要加括号
function* demo() {
console.log('Hello' + yield 'world'); // error
console.log('Hello' + (yield 'world')); // OK
}
注意点三
yield表达式可以作为参数或者出现在赋值号=的右边
function* demo() {
foo(yield 'a'); // OK
let input = yield; // OK
}
注意点四
当调用return函数时,如果当前的yield表达式在try…finally语句中,则会立刻进入finally代码块中执行,直到代码块结束,最后才返回之前return函数的参数
function* numbers () {
yield 1;
try {
yield 2;
yield 3;
} finally {
yield 4;
yield 5;
}
yield 6;
}
var g = numbers();
g.next() // { value: 1, done: false }
g.next() // { value: 2, done: false }
g.return(7) // { value: 4, done: false }
g.next() // { value: 5, done: false }
g.next() // { value: 7, done: true }
最后
以上就是难过小蘑菇为你收集整理的Generator生成器详解generator函数迭代器对象的方法Generator 函数的thisgenerator函数应用注意点的全部内容,希望文章能够帮你解决Generator生成器详解generator函数迭代器对象的方法Generator 函数的thisgenerator函数应用注意点所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复