JavaScript里的迭代器Iterator和生成器Generator(前端) async和await

1.什么是迭代器

2.什么是可迭代对象

3.原生迭代器对象

4.可迭代对象的应用

5.自定义类的迭代

6.迭代器的中断

7.什么是生成器:定义以及生成器的返回值和参数

8. 生成器的终止和生成器的throw

9.生成器的替代迭代器、yield*语法糖、生成器实现自定义类迭代及其for of等操作

10.生成器解决异步:基本实现和自定义执行函数的封装

11.async和await

1.什么是迭代器

迭代器就是实现了next方法的对象,并且next方法需要满足以下要求

1)传入一个或没有参数的函数

2)返回一个对象,对象里包含value和done两个key,当迭代完的时候done返回是true,否则是false,当迭代完毕的时候value值可以省略也可以是其他默认值

let foo={
  next(){
    return {value:1,done:true}
  }
}
console.log(foo.next());

2.什么是可迭代对象

可迭代对象就是对象里实现了[Symbol.iterator]方法,方法里面需要返回一个包含next方法的对象,next方法的要求和迭代器里面的next一样,可迭代对象的特点就是我们可以对其进行for of方法,但是不能map,因为map是Array类上的方法

let foo={
  [Symbol.iterator]:function(){
   let a=0
   return {
      next(){
        if(a<2){
          a=a+1
          return {value:a,done:false}
        }
        return {value:a,done:true}
      }
    }
  }
}
// 当我们把对象变成可迭代对象后 我们就可以进行of循环 
// 返回的值就是next return出来的value值 循环次数就是return出来done为false的次数
for(let i of foo){
  console.log(i);//1 2
}
// 报错
foo.map((item)=>{
  console.log(item);
})

3.原生迭代器对象

原生可迭代对象有String,Array,解构数组,map,set,arguements和获取的dom集合,weakSet和weakMap不属于原生可迭代对象

注意:解构对象不是迭代器

4.可迭代对象的应用

p JavaScript中语法:for ...of、展开语法(spread syntax)、yield*(后面讲)、解构赋值(Destructuring_assignment);
p 创建一些对象时:new Map([Iterable])、new WeakMap([iterable])、new Set([iterable])、new WeakSet([iterable]);
p 一些方法的调用:Promise.all(iterable)、Promise.race(iterable)、Array.from(iterable);
注意:对象可以展开语法是es9做的特殊处理 不是迭代器,解构对象也是

6.可迭代对象的中断

可迭代对象里面可以添加return方法,当我们对这个对象进行for of的时候如果因为break、continue、return、throw中断了循环操作,就会调用return方法,let iterator=foo[Symbol.iterator]()这种调用方式如果return方法调用再调用next依旧会按照之前的继续迭代

let foo={
  [Symbol.iterator]:function(){
   let a=0
   return {
      next(){
        if(a<5){
          a=a+1
          return {value:a,done:false}
        }
        return {value:a,done:true}
      },
      return(){
        console.log('结束');
        return {value:a,done:true}
      }
    }
  }
}
for(let item of foo){
  console.log(item);//1 2 结束
  if(item=='2')break
}
let iterator=foo[Symbol.iterator]()
console.log(iterator.next());//{ value: 1, done: false }
console.log(iterator.return());//{ value: 1, done: true }
console.log(iterator.next());//{ value: 2, done: false }

7.什么是生成器函数:定义以及生成器的返回值和参数

1)定义:生成器就是函数就是一个命名带*,用yield控制执行,返回值是一个空对象,原型是一个可迭代对象,可迭代对象里面有next,return方法,所以我们可以调用next等方法

function* foo(){
  yield 1
}
console.log(foo);//[GeneratorFunction: foo]
console.log(foo());//Object [Generator] {}

JavaScript里的迭代器Iterator和生成器Generator(前端) async和await_第1张图片

 2)返回值:返回值的value的值就是yield里面的值,每次调用一次next,就会执行到yield,如果所有的yield都执行完了,value的值就是undefined,done就是false,如果还有下一次yield,则done是true

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

 3)参数

function *foo(num){
   let n=yield num*2
   let m=yield n*10
   yield m*4
}
let foo1=foo(1)//这个传入的参数是里面的num
console.log(foo1.next(3));//这个传入的参数是没有地方接收的,因为是第一次yield,没有上一次yield  { value: 2, done: false }
console.log(foo1.next(1.5));//这个传入的参数是里面的n  { value: 15, done: false }
console.log(foo1.next(100));//这个传入的参数是里面的m  { value: 400, done: false }

8. 生成器的终止和生成器的throw

1)生成器的终止,注意调用return的时候返回值是return里传入的值

function *foo(num){
   yield 1
   yield 2
   yield 3
}
let foo1=foo()
console.log(foo1.next());//{ value: 1, done: false }
console.log(foo1.return(1.5));//{ value: 1.5, done: true }
console.log(foo1.next());//{ value: undefined, done: true }

2)生成器的throw:调用throw如果有try catch就会到catch里面,执行至下一个yield 然后返回结果

function *foo(num){
  try {
    yield 1
    yield 2
    yield 3
  } catch (error) {
    yield 4
  }
  yield 5
  yield 6
}
let foo1=foo()
console.log(foo1.next());//{ value: 1, done: false }
console.log(foo1.throw(1.5));//{ value: 1.5, done: true }
console.log(foo1.next());//{ value: undefined, done: true }

9.生成器替代迭代器、yield*语法糖、生成器实现自定义类迭代及其for of等操作

因为生成器函数返回 的就是一个原型对象是生成器的对象,所以直接写一个生成器函数就可以替代迭代器了

// 生成器替代迭代器
let obj={
  arr:[1,2,3],
  *[Symbol.iterator](){
    yield* this.arr
  }
}
for(let item of obj){
  console.log(item);//1 2 3
}

// 语法糖 yield*后面需要跟上一个可迭代对象 返回可迭代对象的key
let arr=[1,3]
function *bar() {
 yield* arr    
}
let bar1=bar()
console.log(bar1.next());
// { value: 0, done: false }
// { value: 1, done: false }

class Person{
  arr=[1,2,3];
  // *加在[Symbol.iterator]前面 在生成器里面[Symbol.iterator]函数执行会
  // 返回一个可迭代对象,这样写也是返回一个可迭代对象,所以是等同的
  *[Symbol.iterator](){
    yield* this.arr
  }
}
// 创建可迭代对象 通过new
let per=new Person()
// 由下可知用了生成器创建的可迭代对象也是可以用for of进行循环的
for(let item of per){
  console.log(item);//1 2 3
}

10.生成器解决异步:基本实现和自定义执行函数的封装

// 模拟异步函数
// 为什么要把promise放到函数里面,因为模拟需要多次调用
// 为什么要用promise 而不是直接setTimeout 为了得到上一次的结果
function foo(params) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve(params);
    }, 2000);
  });
}
// 模拟多个异步函数
function* bar(num) {
  let result = yield foo(num);
  let result1 = yield foo(result);
  yield foo(result1);
}
let bar1 = bar(1);
//多个异步函数变成同步的实现
// 方案一
function foo2(params) {
  params.next().value.then((res)=>{
    console.log(res);//1
    params.next(2).value.then((res)=>{
      console.log(res);//2
      params.next(3).value.then((res)=>{
        console.log(res);//3
      })
    })
  })
}
// 方案二 自执行函数
function foo1(params) {
  function exe(res) {
    // 获得的是一个promise
    let data = params.next(res);
    if (!data.done) {
      data.value.then((res) => {
        console.log(res); //1 1 1
        exe(res);
      });
    } else {
      return;
    }
  }
  exe();
}
// 调用
foo1(bar1);
foo2(bar1);

11.async和await

1.async:在函数前面可以加async关键词,代表该函数是一个异步函数,异步函数得返回值如果是一个promise,返回值由promise决定,如果是一个有then方法得函数,则由then决定,异步函数调用后得返回值是一个promise

2.await:只能在async里面使用 加了后需要等await后的执行完才能执行下面的代码并且下面的代码会被放入微任务

如果await后面是一个普通的值,那么会直接返回这个值;

如果await后面是一个thenable的对象,那么会根据对象的then方法调用来决定后续的值;
如果await后面的表达式,返回的Promise是reject的状态,那么会将这个reject结果直接作为函数的Promise的 reject值;

你可能感兴趣的:(JavaScript,javascript,前端,开发语言)