ES6——Generator函数

本文深入探讨了ES6中的Generator函数,包括next方法的使用、for...of循环、异步读取、throw方法处理异常、return方法手动结束遍历、Generator的嵌套以及this的相关特性。还介绍了如何通过Thunk转换多参数为单参数,以便更好地理解和应用Generator函数。


Generator 函数是 ES6 提供的一种 异步编程解决方案
(Generator 函数是一个状态机,封装了多个内部状态)

Generator 函数就是遍历器生成函数

function* 名称
体内 yield 表达式(状态等待执行 并返回)

一、next()方法

1.next不带参

    function* fun(){
        yield 1+1;
        yield 2+2;
        yield 3+3;
        yield 4+4;
        return 10;   //替换最终的value:undefined
    }
    //执行该函数
    let f=fun(); //执行之后返回遍历器
    console.log(f.next()); //{value: 2, done: false}
    console.log(f.next()); //{value: 4, done: false}
    console.log(f.next()); //{value: 6, done: false}
    console.log(f.next()); //{value: 8, done: false}
    console.log(f.next()); //{value: 10, done: true} 
    //不加return,value:undefined

在这里插入图片描述

2.next带参

参数指的是上一次yeild表达式的返回值 (本身是undefined)

    //next遍历带参 参数指的是上一次yeild表达式的返回值(本身是undefined)
    function* method(){
        let x=yield 1+2;
        console.log(x);
        let y=yield 3+x;
        console.log(y);
        return y+10;
    }
    let met=method();
    console.log(met.next()); //{value: 3, done: false}
    console.log(met.next(3)); //3  {value: 6, done: false}
    console.log(met.next(8)); //8  {value: 18, done: true}

3.面试题

(1)yield表达式如果用在另一个表达式之中,必须放在圆括号里面

    function* fun(){
        let x=yield 5+(yield 1+2);
        return x;
    }
    let xf=fun();
    console.log(xf.next()); //{value: 3, done: false}
    console.log(xf.next()); //{value: NaN, done: false}  (5+undefined)
    console.log(xf.next()); //{value: undefined, done: true}
    console.log(xf.next()); //{value: 3, done: false}
    console.log(xf.next(10)); //{value: 15, done: false}  (5+10)
    console.log(xf.next(5)); //{value: 5, done: true}

(2)Generator函数执行 返回遍历器 函数体并没有执行

    function* fm(){
        console.log("start");
        console.log(1,`${yield}`);
        console.log(2,`${yield}`);
        console.log("end");
    }
	let f=fm();  //无返回值
    f.next(); //start
    f.next(5); //1  '5'
    f.next(10); //2  '10'
    f.next(); //end
console.log(f.next()); //start  {value: undefined, done: false}
console.log(f.next('a')); //1 'a' {value: undefined, done: false}
console.log(f.next('b'));//2 'b' end  {value: undefined, done: true}

(3)

    function* fm(){
        console.log(1,`${yield}`);
        console.log(2,`${yield}`);
        console.log("end");
    }
	let f=fm();  //无返回值
    f.next(); //无返回值
    f.next(5); //1  '5'
    f.next(10); //2  '10'  end
console.log(f.next()); //	{value: undefined, done: false}
console.log(f.next('a')); //1 'a' {value: undefined, done: false}
console.log(f.next('b'));//2 'b' end  {value: undefined, done: true}

二、for…of循环

1.for…of

for…of循环可以自动遍历 Generator 函数运行时生成的Iterator对象,且此时不再需要调用next方法

    function* foo(){
        yield 1;
        yield 2;
        yield 3;
        yield 4;
        return 5;
    }
    for(let v of foo()){
        console.log(v);  //1 2 3 4
    }

一旦next方法的返回对象的done属性为true,for…of循环就会中止,且不包含该返回对象
所以上面代码的return语句返回的5,不包括在for…of循环之中

2.其他方法( … ,解构赋值 ,Array.from)

除了for…of循环以外,扩展运算符(…)、解构赋值和Array.from方法内部调用的,都是遍历器接口。
这意味着,它们都可以将 Generator 函数返回的 Iterator 对象,作为参数。

function* numbers () {
  yield 1
  yield 2
  return 3
  yield 4
}

// 扩展运算符
[...numbers()] // [1, 2]

// Array.from 方法
Array.from(numbers()) // [1, 2]

// 解构赋值
let [x, y] = numbers();
x // 1
y // 2

// for...of 循环
for (let n of numbers()) {
  console.log(n)
}
// 1
// 2

三、异步读取

    function* requCity(){
        let result=yield Ajax('get','./city.json',null, function (res) {
            console.log(aja.next(res)); //{value: Array(1), done: true}
        })
        let json=JSON.parse(result);
        return json;
    }
    let aja=requCity();
    aja.next();

city.json:

[
  {"id":"1","name":"陕西","child":[
    {"cid":"1-1","name":"西安"}
  ]}
]

在这里插入图片描述

四、throw() 抛出异常

Generator 函数返回的遍历器对象,都有一个throw方法,可以在函数体外抛出错误,然后在 Generator 函数体内捕获

(1)

var g = function* () {
  try {
    yield;
  } catch (e) {
    console.log('内部捕获', e);
  }
};

var i = g();
i.next();

try {
  i.throw('a');
  i.throw('b');
} catch (e) {
  console.log('外部捕获', e);
}
// 内部捕获 a
// 外部捕获 b

i第二次抛出错误,由于 Generator 函数内部的catch语句已经执行过了,不会再捕捉到这个错误了,所以被函数体的catch语句捕获

(2)

    function* method(){
        try{
            yield 1+2;
            yield 2+3;
            yield 3+4;
        }
        catch(e){
            console.log(e.message);
        }
    }
    let m=method();
    console.log(m.next()); //{value: 3, done: false}
    m.throw(new Error("出错了")); //出错了

五、return() 手动结束遍历

返回给定的值,并且终结遍历 Generator 函数

(1)有参

function* gen() {
  yield 1;
  yield 2;
  yield 3;
}

var g = gen();

g.next()        // { value: 1, done: false }
g.return('foo') // { value: "foo", done: true }
g.next()        // { value: undefined, done: true }

(2)无参

function* gen() {
  yield 1;
  yield 2;
  yield 3;
}

var g = gen();

g.next() // { value: 1, done: false }
g.return() // { value: undefined, done: true }

六、Generator嵌套

    let a= function* () {
        yield 'a';
        yield 'b';
    }
    let b= function* () {
        yield 1;
        yield* a();
        yield 2;
    }
    let bf=b();
    console.log(bf.next()); //{value: 1, done: false}
    console.log(bf.next()); //{value: 'a', done: false}
    console.log(bf.next()); //{value: 'b', done: false}
    console.log(bf.next()); //{value: 2, done: false}
    console.log(bf.next()); //{value: undefined, done: true}

七、this

Generator 函数总是返回一个遍历器,ES6 规定这个遍历器是 Generator 函数的实例,也继承了 Generator 函数的prototype对象上的方法

(1)

function* g() {}

g.prototype.hello = function () {
  return 'hi!';
};

let obj = g();

obj instanceof g // true
obj.hello() // 'hi!'

Generator 函数g返回的遍历器obj,是g的实例,而且继承了g.prototype

但是,如果把g当作普通的构造函数,并不会生效,因为g返回的总是遍历器对象,而不是this对象。

function* g() {
  this.a = 11;
}

let obj = g();
obj.next();
obj.a // undefined

(2)Generator 函数也不能跟new命令一起用,会报错

function* F() {
  yield this.x = 2;
  yield this.y = 3;
}

new F()
// TypeError: F is not a constructor

(3)让 Generator 函数返回一个正常的对象实例,既可以用next方法,又可以获得正常的this

首先,生成一个空对象,使用call方法绑定 Generator 函数内部的this。这样,构造函数调用以后,这个空对象就是 Generator 函数的实例对象了。

function* F() {
  this.a = 1;
  yield this.b = 2;
  yield this.c = 3;
}
var obj = {};
var f = F.call(obj);

f.next();  // Object {value: 2, done: false}
f.next();  // Object {value: 3, done: false}
f.next();  // Object {value: undefined, done: true}

obj.a // 1
obj.b // 2
obj.c // 3

八、Thunk 多参转单参

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

致可乐

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值