【ES6】(三)迭代器Iterator、生成器Generator、Promise、aysnc的用法、class类的用法

一、迭代器Iterator

迭代器是一个接口,能快捷的访问数据。
一个数据结构只要具有Symbol.iterator属性,就可以认为是“可遍历的”

let arr = ['a', 'b', 'c'];
let iter = arr[Symbol.iterator]();

iter.next() // { value: 'a', done: false }
iter.next() // { value: 'b', done: false }
iter.next() // { value: 'c', done: false }
iter.next() // { value: undefined, done: true }

next()方法返回一个对象,这个对象包含valuedone两个属性,value属性返回当前位置的成员,done属性是一个布尔值,表示遍历是否结束,即是否还有必要再一次调用next方法。

原生具备 Iterator 接口的数据结构如下
Array
Map
Set
String
TypedArray
函数的 arguments 对象
NodeList 对象

二、生成器Generator

定义一个生成器函数需要在function后面加*

function* obj(){
}

1、yield

Generator函数每次遍历需要调用next()方法,而next()方法从函数头部或者上一次停下来的地方开始执行,遇到yield表达式就会暂停。所以yield表达式就是暂停标志。

遍历器对象的next方法的运行逻辑如下。

(1)遇到yield表达式,就暂停执行后面的操作,并将紧跟在yield后面的那个表达式的值,作为返回的对象的value属性值。

(2)下一次调用next方法时,再继续往下执行,直到遇到下一个yield表达式。

(3)如果没有再遇到新的yield表达式,就一直运行到函数结束,直到return语句为止,并将return语句后面的表达式的值,作为返回的对象的value属性值。

(4)如果该函数没有return语句,则返回的对象的value属性值为undefined。

function* add() {
    console.log('start');
    let x = yield '2';
    console.log('one:' + x);
    let y = yield '3';
    console.log('two:' + y);
    return x + y;
}
const fn = add();
console.log(fn.next(20));   // start   {value: '2', done: false}
console.log(fn.next(20)); // one:20  {value: '3', done: false}
console.log(fn.next(30)); // two:30  {value: 50, done: true}
console.log(fn.next());   // {value: undefined, done: true}

在这里面我们会发现,当我们第一次调用next,并赋值20的时候,x并没有被赋值,这是因为yield暂停了,只有当下一次调用next并赋值,才会对上一个赋值

2、Generator与 Iterator 接口的关系

之前我们说到,只要对象有Symbol.iterator属性,就可以调用该方法生成一个迭代器遍历对象,那么当对象没有iterator接口,我们该如何添加?

只需要把 Generator 赋值给对象的Symbol.iterator属性,从而使得该对象具有 Iterator 接口。

var obj = {};
obj[Symbol.iterator] = function* () {
  yield 1;
  yield 2;
  yield 3;
};

[...obj] // [1, 2, 3]

三、Promise

这章节看文档吧,文档写的更好

四、aysnc的用法

async 函数是什么?一句话,它就是 Generator 函数的语法糖。
作用:使异步操作更加方便

当你给函数前面加上async,这个函数就会变成Generator函数

当我们定义一个函数obj,把它变为Generator是这样的:

const obj = function* () {
  const f1 = yield 1;
  const f2 = yield 2;
  console.log(f1);
  console.log(f2);
};

当我们用async函数写是这样的:

const obj = async function() {
  const f1 = await 1;
  const f2 = await 2;
  console.log(f1);
  console.log(f2);
};

一比较就会发现,async函数就是将 Generator 函数的星号(*)替换成async,将yield替换成await,仅此而已。

1、async函数对 Generator 函数的改进,体现在以下四点:

(1)内置执行器。
Generator函数的执行必须靠执行器,所以才有了co模块,而async函数自带执行器。也就是说,async函数的执行,与普通函数一模一样,只要一行。

asyncReadFile();
上面的代码调用了asyncReadFile函数,然后它就会自动执行,输出最后结果。这完全不像Generator 函数,需要调用next方法,或者用co模块,才能真正执行,得到最后结果。

(2)更好的语义。

async和await,比起星号和yield,语义更清楚了。async表示函数里有异步操作,await表示紧跟在后面的表达式需要等待结果。

(3)更广的适用性。

co模块约定,yield命令后面只能是 Thunk 函数或 Promise 对象,而async函数的await命令后面,可以是Promise 对象和原始类型的值(数值、字符串和布尔值,但这时会自动转成立即 resolved 的 Promise 对象)。

(4)返回值是 Promise。

async函数的返回值是 Promise 对象,这比 Generator 函数的返回值是 Iterator对象方便多了。你可以用then方法指定下一步的操作。

进一步说,async函数完全可以看作多个异步操作,包装成的一个 Promise 对象,而await命令就是内部then命令的语法糖。

2、返回 Promise 对象

定义的async函数,里面的return语句返回的值,会成为then方法回调函数的参数

async function f() {
  return 'hello world';
}

f().then(v => console.log(v))
// "hello world"

3、await

处理异步操作有三个状态(1)Pending(进行)(2)Resolved (成功)(3)Rejected (失败)

async函数内部抛出错误,会导致返回的 Promise 对象变为reject状态。抛出的错误对象会被catch方法回调函数接收到。

async function f() {
  throw new Error('出错了');
}

f().then(
  v => console.log('resolve', v),
  e => console.log('reject', e)
)
//reject Error: 出错了

只要await语句后面的Promise对象变为了reject状态,name整个async函数就会中断执行

假如我们希望在一个异步操作失败,但也不要中断后面的异步操作的时候,可以将第一个await放在try…catch结构里面,然后catch里面不写东西,如果出现错误,就会自动跳过当前await

async function f() {
    try {
        await Promise.reject('出错了');
    } catch (e) {
    }
    return await Promise.resolve('hello world');
}

f().then(v => console.log(v));
// hello world

await命令只能用在async函数之中,如果用在普通函数,就会报错

这一块和promise一样多看文档吧,后面我把promise学会练熟再多理解

五、class类的用法

在ES5中构造函数造类是这样的:


        function Person(name,age) {
            this.name = name;
            this.age = age;
        }
        Person.prototype.sayName = function(){
            return this.name;
        }
        let p1 = new Person('zh',22);
        console.log(p1); // Person {name: 'zh', age: 22}

在ES6中造类是这样的:

class Person1{
    constructor(name,age){
        this.name = name;
        this.age = age;
    }
    sayName(){
        return this.name;
    }
    sayAge(){
        return this.age;
    }
}
let p2 = new Person1('zh',22);
console.log(p2); // Person1 {name: 'zh', age: 22}

1、类的继承extends

Class可以通过extends关键字实现继承,让子类继承父类的属性和方法。

定义一个People类继承上面的Person类的方法:

class People extends Person {
            constructor(name, age, color) {
                super(name, age);
                this.color = color;
            }
        }
let zh = new People('zh', 22, 'blue');
console.log(zh); // People {name: 'zh', age: 22, color: 'blue'}

super在这里表示父类的构造函数,用来新建一个父类的实例对象。注意:super一定要写在this前面

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值