【JavaScript】ES6~ES13,Proxy,Reflect,Promise,生成器,async/await

❤️ Author: 老九
☕️ 个人博客:老九的CSDN博客
🙏 个人名言:不可控之事 乐观面对
😍 系列专栏:

ES6

  • ES6(ECMAScript 6)是JavaScript的第六个版本,也称为ECMAScript 2015。它是ECMAScript标准的一个重要更新,引入了许多新的语言特性和改进,为JavaScript开发者提供了更强大、更灵活的工具和语法。

let const

  • let 和 var差不多,但是不能重复声明变量
  • const用于保存一些常量,保存的数据一旦被赋值,就不能被修改
  • var声明的变量作用域会提升,但是let在声明之前访问就会报错,从块作用域的顶部一直到变量声明完成之前,这个变量处在暂时性死区
  • 在全局通过var来声明一个变量,事实上会在window上添加一个属性,但是let,const是不会给window上添加任何的属性

块级作用域

作用域分为全局作用域,函数作用域,块级作用域
在这里插入图片描述
在ES5众,放到一个代码中定义的变量,外面是可以访问到的
在这里插入图片描述
但是在ES6众新增了块级作用域,并通过let,const,function,class的标识符是巨鳖块级作用域的限制的
在这里插入图片描述
这里我们需要注意,函数function拥有块级作用域,但是外面依然可以访问到,这是因为JS引擎会对函数的声明进行特殊的处理,允许像var那样进行提升

模板字符串,标签模板字符串

  • 在ES6之前,拼接字符串很复杂,es6使用反引号和${}拼接字符串
  • 标签模板字符串:(用在styled-components库)
    在这里插入图片描述

函数的默认参数

  • es6增加了函数的默认参数
    在这里插入图片描述

函数的剩余参数

  • 如果最后一个参数是…为前缀的,那么它会将剩余的参数放到该参数中,并且作为一个数组,剩余参数要放在最后一个位置
    在这里插入图片描述

剩余参数和arguments有什么区别?

  • 剩余参数值包含那些没有对应形参的实参,arguments对象包含传给函数所有的实参;
  • arguments对象不是一个真正的数组,而…参数是一个真正的数组,可以进行数组的所有操作
  • arguments是早期ECMAScript中为了方便去获取所有参数提供的一个数据结构,而。。。是es6中提供代替arguments的

箭头函数

  • 箭头函数没有显示原型Prototype的,不能作为构造函数
  • 箭头函数也不绑定,this,arguments,super参数

展开语法

  • 在函数调用/数组构造时,将数组表达式或者string在语法层面展开
  • 还可以构造对象时,将对象表达式按照key-value的方式展开
    在这里插入图片描述
  • 展开语法是一个浅拷贝

浅拷贝/深拷贝

  • 这个就叫做引用赋值,和展开语法是一样的,都是浅拷贝
    - List item
  • 这样,如果你修改了其中一个变量所引用的对象,另一个变量也会反映这些修改,因为它们引用的是同一个对象。
    在这里插入图片描述
  • 如果想实现深拷贝,需要自己实现。其中一种方法是利用JSON的机制来实现深拷贝。
    const info3 = JSON.parse(JSON.stringify(obj));
  • JSON深拷贝的弊端,函数和方法丢失:JSON只能序列化对象的数据,不能序列化对象的方法和函数。当进行深拷贝时,函数和方法将丢失,只有数据被复制。循环引用问题:如果对象存在循环引用,即对象之间相互引用,JSON无法正确处理这种情况。在序列化和反序列化过程中,JSON会陷入循环引用的无限循环中,导致堆栈溢出或内存泄漏。特殊对象丢失:JSON无法序列化特殊对象,例如正则表达式、日期对象、Map、Set等。这些对象在序列化和反序列化后,将丢失它们的原始类型和功能。原型链丢失:JSON无法序列化对象的原型链信息。在深拷贝后,所有对象的原型都将丢失,它们只是简单的数据对象,无法访问原型链上的方法和属性。

深拷贝实现

 <!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <script>
      //判断是不是对象
      function isObject(value) {
        const valueType = typeof value; // null,object,function,array
        return (
          value !== null && (valueType === "object" || valueType === "function")
        );
      }
      function deepCopy(originValue, map = new WeakMap()) {
        //通过map解决循环引用,
        //1.如果是原始类型,直接返回
        if (!isObject(originValue)) {
          return originValue;
        }
        //2.如果是对象类型,才需要创建对象
        if (map.get(originValue)) {
          return map.get(originValue);
        }
        const newObj = Array.isArray(originValue) ? [] : {};
        map.set(originValue, newObj);
        for (const key in originValue) {
          newObj[key] = deepCopy(originValue[key], map);
        }

        return newObj;
      }
      const info = {
        name: "why",
        age: 18,
        friend: {
          name: "kobe",
          address: {
            name: "洛杉矶",
            detail: "lmp",
          },
        },
      };
      info.self = info;
      const newObj = deepCopy(info);
      console.log(newObj);
    </script>
  </body>
</html>

数值的表示

在ES6中,规范了二进制和八进制的写法
在这里插入图片描述

Symbol

  • ES6中新增的一个基本数据类型。
  • 在es6之前编写一个属性,对象的属性名都是字符串,如果不是字符串,就会调用toString()方法改成字符串,那么很容易造成属性名冲突;
  • Symbol就是为了解决这个问题,用于生成一个独一无二的值。通过一个Symbol函数生成的 const s1 = Symbol(),es6之后,对象的属性名就既可以是字符串又可以是Symbol了
    在这里插入图片描述
  • 使用方法的话可以这么写
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
  • Object.keys()方法会返回一个由一个给定对象的自身可枚举属性组成的数组
  • 通常我们获取对象的key的时候,通过Object.keys(obj)实现,但是这个方法获取不到Symbol作为key,需要通过Object.getOwnPropertySymbols(obj)单独获取Symbol作为key的字段
    在这里插入图片描述
  • Symbol()里面的()可以描述Symbol,通过s.description可以获取Symbol的描述
    在这里插入图片描述
  • 我们通过Symbol.for可以生成相同的Symbol;通过Symbol.keyFor方法来获取对应的key
    在这里插入图片描述

Set

  • 在ES6之前,我们存储数据的结构主要有:数组,对象
  • 在ES6中新增了另外两种数据结构,Set,Map,以及他们的另外形式WeakSet,WeakMap
  • Set是一个新增的数据结构,可以用来保存数据,里面的数据不能重复,通过构造函数创建
    在这里插入图片描述
    set的常见方法
    在这里插入图片描述
  • 作用:数组的去重,Array.from(new Set(数组))/[…new Set(数组)]

WeakSet

  • 内部元素不能重复
  • 区别一:但是只能存放对象类型,不能存放基本数据类型;区别二:对元素的引用是弱引用,如果没有其他引用对某个对象进行引用,那么GC可以对该对象进行回收
  • 因为WeakSet只是对对象的弱引用,如果我们遍历获取到其中的元素,那么有可能造成对象不能正常销毁,所以存储到WeakSet中的对象是没办法获取的,WeakSet不能遍历

Map

  • Map用于存储映射关系,但是使用对象也可以存储映射关系;对象存储映射关系只能用字符串(ES6新增了Symbol)作为属性名(key),某些情况下,我们希望通过其他类型作为key,比如对象,这时候就可以使用map
    在这里插入图片描述
    map常用方法
    在这里插入图片描述

WeakMap

  • 和map的区别一:WeakMap的key只能使用对象,不接受其他的类型作为key;区别二:WeakMap的key对对象的引用是弱引用,如果没有其他引用引用这个对象,那么GC可以回收该对象
  • 注意WeakMap也是不能遍历的

Proxy

  • 下面是vue2的响应式原理,但是这样写是有弊端的,首先Object.defineProperty的设计的初衷,不是为了去监听一个对象的所有属性,其次我们如果想监听更加丰富的操作,比如新增属性,删除属性,那么Object.defineProperty是不行的,这是就出现了Proxy对象,这个是专门用作监听对象而生成的。
      const keys = Object.keys(obj);
      for (const key of keys) {
        let value = obj[key];
        Object.defineProperty(obj, key, {
          set: function (newValue) {
            value = newValue;
          },
          get: function () {
            return value;
          },
        });
      }
  • 在ES6中,新增了一个Proxy类,帮助我们创建一个代理对象,如果我们希望监听一个对象的相关操作,那么我们可以先创建一个代理对象,之后对该对象的所有操作,都通过代理对象完成,代理对象可以监听我们想要对原对象进行哪些操作
  • 首先我们需要new Proxy对象,传入需要监听的对象和一个处理对象,称之为handler;const p = new Proxy(target,handler),之后我们所有的操作都是直接对Proxy对象的操作,而不是原有的对象
   var obj = {
        name: "lmp",
        age: 18,
        height: 1.88,
      };

      //1.创建一个代理对象
      const objProxy = new Proxy(obj, {
        //编写set和get捕获器
        //get函数有三个参数:1.target:目标对象(侦听的对象)
        //2.property:被捕获 的属性key
        //3.receiver:调用的代理对象
        get: function (target, key) {
          console.log(`监听${key}的获取`);
          return target[key];
        },
        //set函数有四个参数
        //1.target:目标对象
        //property:将被设置的属性key
        //value:新属性值
        //receiver:调用的代理对象
        set: function (target, key, newValue) {
          console.log(`监听${key}的设置值:`, newValue);
          target[key] = newValue;
        },
        deleteProperty: function (target, key) {
          delete obj.name;
        },
        has: function (target, key) {
          return key in target;
        },
      });

      //2.对obj的所有操作,应该去操作objProxy
      console.log(objProxy.name);
      objProxy.name = "why";
      delete objProxy.name;
      console.log(objProxy.name, 111);
  • 函数也是一个对象,所以函数也是可以监听的,监听器例如apply函数,construct函数

Reflect

  • 这个本身是一个对象,字面意思是反射,它提供了操作JavaScript对象的方法,类似于Object中操作对象的方法。例如获取原型对象Reflect.getPrototypeOf(target),定义对象属性Reflect.defineProperty(target,propertyKey,attributes)
  • 如果我们有Object可以做这些操作,为什么还需要Reflect这样的新增对象呢?
  • 早期的ECMA规范中没有考虑到对象本身的操作如何设计更加规范,所以将这些API放在Object上面,但是Object作为一个构造函数,放到它的身上是不合适的,ES6增加了Reflect,让这些操作都集中到了Reflect对象上
  • 区别1:delete操作,使用Reflecct.deleteProperty可以返回一个布尔值
    在这里插入图片描述
  • Reflect一般配合Proxy配合使用
      const objProxy = new Proxy(obj, {
        set: function (target, key, newValue, receiver) {
          //好处1:不再操作直接对象
          //好处2:Reflect.set方法有返回Boolean值,可以判断本次操作是否成功
          //好处3:Reflect可以设置Receiver
          /*
            receiver就是外层的Proxy对象
            Reflect.set/get最后一个receiver参数,可以决定对象访问器Setter/Getter的this指向,可以实现监听两次,默认this是指向元对象obj的,增加recceiver参数后,就可以改变this的指向了
          */
          const isSuccess = Reflect.set(target, key, newValue);
          if (!isSuccess) {
            throw new Error("error");
          }
        },
      });

ES7

Array Includes

  • 在ES7之前,如果我们想判断一个数组中是否包含某个元素,可以通过indexOf获取结果,并且判断是否为-1
  • 在ES7中,我们可以通过includes来判断一个数组中是否包含一个指定的元素,根据情况,包含返回true,不包含返回false
    在这里插入图片描述

指数运算符

在这里插入图片描述

ES8

Object.values

  • 之前我们通过Object。keys获取一个对象所有的key
  • 在ES8中提供Object.values来获取所有的value值
    在这里插入图片描述

Object.entries

  • 通过Object.entries可以获取到一个数组,数组中存放可枚举属性的键值对数组
  • 可以针对对象,数组,字符串进行操作
    在这里插入图片描述

padStart、padEnd

  • 某些字符串我们需要对其进行前后的填充,来实现某种格式化效果,ES8中增加了padStart和padEnd方法,分别对象字符串的首尾进行填充
    在这里插入图片描述
    在这里插入图片描述

Trailing Commas

  • 在ES8中,允许我们在函数的定义和调用时多加一个逗号
    在这里插入图片描述

ES10

flat flatMap

  • flat方法会按照一个可指定的深度递归遍历数组
    在这里插入图片描述
  • flatMap方法,首先使用映射函数映射每个元素,然后将结果压缩成一个新数组
    在这里插入图片描述

Object fromEntries

  • 可以通过Object.entries将一个对象转换成entries、那么现在有一个entries,通过fromEntries转换成对象
    在这里插入图片描述
    Object.fromEntries的实际用法
    在这里插入图片描述

ES11

trimStart和trimEnd

  • 去除一个字符串首尾的空格,通过trim方法,单独去除前面或后面的空格,用trimStart和trimEnd
    在这里插入图片描述

BigInt

  • 早期的JS中,不能正确的表示过大的数字,大于MAX_SAFE_INTEGER的数值,表示的是不正确的
    在这里插入图片描述
    在ES11中,引入新的数据类型BigInt,用于表示大的整数
    BigInt的表示方法是在数值后面加上n
    在这里插入图片描述

可选链

  • 主要作用是让我们的代码在进行null和undefined判断时更加清晰和简洁
    在这里插入图片描述

for … in

  • 在ES11之前,虽然很多浏览器支持for in 来遍历对象类型,但是并没有被ECMA标准化
  • ES11中,对其进行了标准化,for in用于遍历对象的key
    在这里插入图片描述

在这里插入图片描述

ES12

数字过长时候使用_连接

在这里插入图片描述

Promise

异步处理代码的困境

  • 在以前都是自己设计异步代码,这样设计代码的和调用者可能不是同一个人,会有很多的麻烦
  function execCode(counter, successCallback, failCallback) {
        setTimeout(() => {
          if (counter <= 0) failCallback(`${counter}值有问题`);
          let total = 0;
          for (let i = 0; i < counter; i++) {
            total += i;
          }
          successCallback(total);
        }, 3000);
      }

      execCode(
        100,
        (total) => {
          console.log(total);
        },
        (err) => {
          console.log(err);
        }
      );
  • 因此出现了promise,promise就像一个通知器一样,告诉你成功了还是失败了
  • Promise是一个类,当我们需要的时候,promise给予调用者一个承诺,待会给你回调数据,当通过new创建Promise对象时,我们需要传入一个回调函数,称为executor,这个回调函数会立即执行,并传入另外两个回调函数,resolve,reject,分别对应.then,.catch,注意:一旦状态被确定,Promise的状态就会被锁死,不会改变
function execCode(counter) {
        const promise = new Promise((resolve, reject) => {
          setTimeout(() => {
            if (counter <= 0) {
              reject("error");
            }
            let total = 0;
            for (let i = 0; i < counter; i++) {
              total += i;
            }
            resolve(total);
          }, 3000);
        });

        return promise;
      }

      const promise = execCode(100);
      promise
        .then((value) => {
          console.log(value);
        })
        .catch((error) => {
          console.log(error);
        });

promise的三种状态

  • 当还没有调用回调函数(resolve,reject),处理待定状态;当操作成功,执行resolve,表示promise成功兑现,reject就是失败了。
  • Promise的状态一旦确定下来,就不会再更改,也不会再执行某一个回调函数来改变状态。

resolve方法的参数

  • resolve的括号里可以传什么值:1.普通值(字符串,对象,数组等)2.promise,如果传入的值是Promsie对象,那么当前的Promise的状态会由传入的Promise状态来确定

then方法

  • then方法可以传两个参数,第一个是成功的回调函数,第二个也可以传失败的回调函数.then(res=>{},err=>{})
  • promise.then之后的返回值是一个新的Promise对象,如果是链式调用的话,第二个then是等待第一个then的返回值进行决议的,如果抛出异常了,就会中断函数执行
    在这里插入图片描述

finally

  • 这个是ES9新增的方法,用在Promise中
    在这里插入图片描述

promise中的类方法

resolve

  • 上面的下面的代码是一样的
    在这里插入图片描述在这里插入图片描述

reject

  • 和resolve用法一样
    在这里插入图片描述

all

  • 将多个Promise包裹在一起形成一个新的Promise;新的Promise状态由包裹的所有Promise共同决定,当所有的Promise状态编程fulfilled状态时,新的Promise状态为fulfilled,并会将所有Promise的返回值组成一个数组;当由一个Promise状态为reject时候,新的Promise状态为reject,并会将第一个reject的返回值作为参数
    在这里插入图片描述

allSettled

  • all方法有一个缺陷,当其中一个Promise变成reject状态时,新的Promise就会立即变成对应的reject状态;那么对于resolved的,依然处于pending状态的Promise,我们获取不到对应的结果
  • 在ES11中,新增了allSettled的api,该方法会在所有Promise都有结果,无论是fulfilled还是rejected时,才会有最终的状态,并且这个Promise的结果一定是fulfilled的,返回的是一个数组对象,对象中一个是status是状态是rejected还是fulfilled,如果是reject,还有个字段就是reason,如果是fulfilled,就拿到value
    在这里插入图片描述

race

  • 如果有多个Promise相互竞争,谁先有结果,就用谁的。
    在这里插入图片描述

手写Promise

class MyPromise {
  #state = 'pending';//promise的初始状态为pending
  #value = undefined;//存储解析值
  #reason = undefined;//存储拒绝原因
  #onResolveCallbacks = [];//存储成功回调函数的数组
  #onRejectCallbacks = [];//存储失败回调函数的数组

  constructor(executor) {
    //构造函数接受两个参数:resolve和reject
    const resolve = (value) => {
      if (this.#state === 'pending') {
        this.#state = 'fulfilled';// 将 Promise 状态设置为 fulfilled(已完成)
        this.#value = value;// 存储解析值
        setTimeout(() => {
            // 异步执行所有已注册的成功回调函数,yinweipromise执行是在事件循环的微任务中
          for (const callback of this.#onResolveCallbacks) {
            callback(this.#value);
          }
        });
      }
    };

    const reject = (reason) => {
      if (this.#state === 'pending') {
        this.#state = 'rejected';// 将 Promise 状态设置为 rejected(已拒绝)
        this.#reason = reason;// 存储拒绝原因
        setTimeout(() => {
          if (this.#onRejectCallbacks.length) {
            // 如果存在已注册的失败回调函数,则异步执行它们
            for (const callback of this.#onRejectCallbacks) {
              callback(this.#reason);
            }
          } else {
            // 如果没有注册的失败回调函数,则抛出拒绝原因
            throw this.#reason;
          }
        });
      }
    };

    try {
      executor(resolve, reject);// 执行器函数接收两个参数,并在创建Promise的时候直接调用 resolve 或 reject
    } catch (error) {
      reject(error);// 如果执行器函数抛出错误,则将 Promise 状态设置为 rejected
    }
  }

  then(onFulfilled, onRejected) {
    return new MyPromise((resolve, reject) => {
      const resolveWrapper = (value) => {
        try {
          const result = onFulfilled(value);
          resolve(result);
        } catch (error) {
          reject(error);
        }
      };

      const rejectWrapper = (reason) => {
        try {
          const result = onRejected(reason);
          resolve(result);
        } catch (error) {
          reject(error);
        }
      };

      if (this.#state === 'fulfilled') {
        setTimeout(() => {
          resolveWrapper(this.#value);
        });
      } else if (this.#state === 'rejected') {
        setTimeout(() => {
          rejectWrapper(this.#reason);
        });
      } else {
        this.#onResolveCallbacks.push(resolveWrapper);
        this.#onRejectCallbacks.push(rejectWrapper);
      }
    });
  }

  catch(onRejected) {
    return this.then(null, onRejected);
  }
}

function asyncTask() {
  return new MyPromise((resolve, reject) => {
    setTimeout(() => {
      const randomNumber = Math.random();
      if (randomNumber < 0.5) {
        resolve(randomNumber);
      } else {
        reject(new Error("Random number is greater than or equal to 0.5"));
      }
    }, 1000);
  });
}

asyncTask()
  .then((result) => {
    console.log("Resolved:", result);
    return result * 2;
  })
  .then((result) => {
    console.log("Resolved:", result);
  })
  .catch((error) => {
    console.log("Rejected:", error.message);
  });

手写promise.all

  • 当所有的 Promise 都变为已解决状态时,新的 Promise 才会被解决,且解决值是一个包含所有已解决 Promise 值的数组,顺序与原始 Promise 数组的顺序相同。
    如果任何一个 Promise 变为拒绝状态,新的 Promise 就会被拒绝,并返回第一个拒绝的 Promise 的原因。
function promiseAll(promises) {
  return new Promise((resolve, reject) => {
    const results = []; // 用于存储所有 Promise 对象的解析值
    let completedCount = 0; // 已完成的 Promise 数量计数

    for (let i = 0; i < promises.length; i++) {
      promises[i]
        .then((result) => {
          results[i] = result; // 将 Promise 对象的解析值存入对应的索引位置
          completedCount++;

          if (completedCount === promises.length) {
            // 当所有 Promise 对象都完成时,解析返回的 Promise 对象,并传递结果数组
            resolve(results);
          }
        })
        .catch(reject); // 如果有任何一个 Promise 对象被拒绝,直接拒绝返回的 Promise 对象
    }

    if (promises.length === 0) {
      // 处理空的 Promise 数组,直接解析并返回空结果数组
      resolve(results);
    }
  });
}

// 示例
const promise1 = new Promise((resolve) => {
  setTimeout(() => {
    resolve('Promise 1');
  }, 1000);
});

const promise2 = new Promise((resolve) => {
  setTimeout(() => {
    resolve('Promise 2');
  }, 2000);
});

const promise3 = new Promise((resolve, reject) => {
  setTimeout(() => {
    reject(new Error('Promise 3 rejected'));
  }, 1500);
});

promiseAll([promise1, promise2])
  .then((results) => {
    console.log(results); // 输出: ['Promise 1', 'Promise 2']
  })
  .catch((error) => {
    console.log(error); // 输出: Error: Promise 3 rejected
  });

手写Promise.race

  • 只要有一个 Promise 状态变为已解决或已拒绝,新的 Promise 就会被解决或拒绝,且结果是第一个完成的 Promise 的值或原因。
      function isPromise(val) {
        if ((!val && typeof val === "object") || typeof val === "function") {
          if (typeof val.then === "function") {
            return true;
          }
        } else {
          return false;
        }
      }
      function promiseRace(promises) {
        return new Promise((resolve, reject) => {
          for (let i = 0; i < promises.length; i++) {
            let value = promises[i];
            if (value && isPromise(value)) {
              value
                .then((result) => {
                  resolve(result); // 一旦有一个 Promise 对象解析完成,立即解析返回的 Promise 对象,并传递解析值
                })
                .catch((error) => {
                  (error) => reject(error);
                });
            } else {
              reject(error); // 如果有任何一个 Promise 对象被拒绝,直接拒绝返回的 Promise 对象,并传递拒绝的原因
            }
          }
        });
      }

手写promise.any

  • 只要有一个 Promise 状态变为已解决,新的 Promise 就会被解决,且结果是第一个已解决的 Promise 的值。
    如果所有的 Promise 都变为拒绝状态,新的 Promise 就会被拒绝,并返回一个包含所有拒绝原因的 AggregateError。
      function promiseAny(promises) {
        return new Promise((resolve, reject) => {
          let errors = []; //存储拒绝的Promise错误
          let resolved = false; // 标记是否已解决一个Promise,确保值关注第一个Pormise被rosolve的值

          promises.forEach((promise) => {
            promise
              .then((value) => {
                if (!resolved) {
                  resolved = true;
                  resolve(value);
                }
              })
              .catch((error) => {
                errors.push(error);
                if (errors.length === promises.length) {
                  reject(errors);
                }
              });
          });
        });
      }

生成器

  • 生成器使ES6中新增的一种函数控制,使用的方案,它让我们更加灵活的控制函数什么时候继续执行,暂停执行。
  • 平时我们编写函数,这些函数种植的条件通常使返回值或者发生了异常
  • 生成器也是一个函数,但是和普通的函数有一些区别;
    1.生成器函数在function后面加一个*
    2.生成器函数可以通过yield关键字来控制函数的执行流程
    3.生成器函数返回值是一个Generator生成器,生成器是一种特殊的迭代器 ,要想生成器执行,调用它的next方法
    在这里插入图片描述
  • next的返回值跟迭代器对象一样,也是返回一个value和一个done,如果想返回value,可以在yield后面写上东西
    在这里插入图片描述
    在这里插入图片描述
  • 如果想传一个参数,写在yield前面加参数,第一次传参数传到foo
    在这里插入图片描述
    在这里插入图片描述
  • 如果想让生成器提前结束,通过return
    在这里插入图片描述
    在这里插入图片描述

生成器代替迭代器

在这里插入图片描述

生成器yield*语法糖

  • yield是一个语法糖,如果我们写成yield*,后面跟了一个可迭代对象,那么就可以自动每次迭代其中一个值

在这里插入图片描述

异步处理

  • 如果有一个需求第二次调用网络请求基于第一次,我们先封装了一个requestData的异步函数,可以使用callback,我们这里使用假promise,这样的话会导致回调地狱
 function requestData(url) {
        return new Promise((resolve, reject) => {
          setTimeout(() => {
            resolve(url);
          });
        });
      }

在这里插入图片描述

  • 使用Promise进行重建,通过return出去给下一个请求调用,改为链式调用,而不是嵌套调用
    在这里插入图片描述

  • 我们可以通过生成器进行实现
    在这里插入图片描述

  • 最终通过async,await就可以实现
    在这里插入图片描述

async,await

  • 这是在ES7新增的语法,前面加上async的函数叫做异步函数
  • 异步函数返回一个promise
  • 在异步函数中,我们才可以使用await;await后面会跟上一个函数,这个函数返回一个Promise,然后await会等待Promise有结果之后,才会继续执行后续的代码,相当于把异步代码变成了同步代码
    在这里插入图片描述

————————————————————————
♥♥♥码字不易,大家的支持就是我坚持下去的动力♥♥♥
版权声明:本文为CSDN博主「亚太地区百大最帅面孔第101名」的原创文章

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

李小浦

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

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

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

打赏作者

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

抵扣说明:

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

余额充值