ES6+进阶笔记

ES6

Promise 异步

前置知识

同步和异步
同步和异步是一种消息通知机制

同步阻塞: 上一件事做完了,才能做下一件事
    A 调用 B,B 处理获得结果,才返回给 A。
    A 在这个过程中,一直等待 B 的处理结果,拿到结果, 然后继续往下执行。

异步非阻塞: 上一件事没有做完,就可以做下件事
    A 调用 B,无需等待 B 的结果,B 通过状态,通知等来通知 A 或回调函数来处理。
    调用结果返回时, 会以消息或回调的方式通知调用者。

在 JS 中正常的代码执行,全部走的都是同步模式,必须拿到一行的执行结果,再执行下一行。
回调地狱
最早我们处理异步消息通知,都是通过回调来处理的。
如果嵌套过多,会极大影响代码可读性和逻辑,这种情况也被成为回调地狱。
fn("first", function () {
  fn("second", function () {
    fn("third", function () {
      console.log("end");
    });
  });
});

Promise

描述
Promise 对象,就是代表了未来某个将要发生的事件(通常是一个异步操作)。
Promise 不解决异步问题,解决的是异步的写法,避免了层层嵌套的回调函数。
基本语法
new Promise(function (resolve, reject) {});

// resolve(传递给成功的执行函数的数据) 代表异步执行完成,并成功拿到结果

// reject(传递给处理失败的执行函数的数据) 代表异步执行完成,但是没有成功拿到结果
内部状态
  • Pending 在等待(异步执行中)
  • Fulfilled(标准) | Resolved 执行成功 调用 resolve() 之后改变
  • Rejected 执行失败 调用 reject() 之后改变
方法
then(onFulfilled,onRejected)
参数:
    onFulfilled
        当Promise变成成功状态时,该参数作为回调函数被调用。该函数有一个参数,即resolve传入的参数。
        如果传入的 onFulfilled 不是函数,则会在内部被替换为(x) => x ,即原样返回 promise 最终结果的函数。

    onRejected
        当Promise变成拒绝状态(rejection )时,该参数作为回调函数被调用,该函数有一个参数,即拒绝的原因。

返回值:
    当一个Promise成功或者失败,返回函数将被异步调用(由当前的线程循环来调度完成)。
    具体的返回值依据以下规则返回:
        - 如果then中的回调函数返回一个值,那么then返回的Promise将会成为接受状态,并且将返回的值作为接受状态的回调函数的参数值。
        - 如果then中的回调函数没有返回值,那么then返回的Promise将会成为接受状态,并且该接受状态的回调函数的参数值为 undefined。
        - 如果then中的回调函数抛出一个错误,那么then返回的Promise将会成为拒绝状态,并且将抛出的错误作为拒绝状态的回调函数的参数值。
        - 如果then中的回调函数返回一个已经是接受状态的Promise,那么then返回的Promise也会成为接受状态,并且将那个Promise的接受状态的回调函数的参数值作为该被返回的Promise的接受状态回调函数的参数值。
        - 如果then中的回调函数返回一个已经是拒绝状态的Promise,那么then返回的Promise也会成为拒绝状态,并且将那个Promise的拒绝状态的回调函数的参数值作为该被返回的Promise的拒绝状态回调函数的参数值。
        - 如果then中的回调函数返回一个未定状态(pending)的Promise,那么then返回Promise的状态也是未定的,并且它的终态与那个Promise的终态相同;同时,它变为终态时调用的回调函数参数与那个Promise变为终态时的回调函数的参数是相同的。
Promise.reject()
Promise.reject(reason) 返回一个状态为 Rejected 的 Promise 对象

参数:
reason 失败原因
Promise.resolve()
Promise.resolve(value) 返回一个状态为 resolved 的 Promise 对象

参数:
value 将被 Promise 对象解析的参数
Promise.catch()
捕获前一个promise抛出的错误
Promise.all(iterable)
接收一个可迭代对象,包装成一个新的Promise实例,当所有Promise都成功的时候,整个Promise.all才成功。
Promise.race(iterable)
接收一个可迭代对象,哪个最先执行完成,则返回其状态(无论成功与否)

Iterator

遍历器(Iterator)就是这样一种机制。
它是一种接口,为各种不同的数据结构提供统一的访问机制。
任何数据结构只要部署 Iterator 接口,就可以完成遍历操作(即依次处理该数据结构的所有成员)。

作用

  1. 为各种数据结构,提供一个统一的、简便的访问接口;
  2. 使得数据结构的成员能够按某种次序排列;
  3. ES6 创造了一种新的遍历命令 for...of循环,Iterator 接口主要供 for...of消费。

迭代协议

可迭代协议

要成为可迭代对象, 一个对象必须实现 @@iterator 方法。
即对象(或者它原型链上的某个对象)必须有一个键为 @@iterator 的属性,可通过常量 Symbol.iterator访问该属性。

迭代器协议

只有实现了next()方法,一个对象才能成为迭代器。

next():必须返回一个对象,该对象应当有两个属性:
    done
        如果迭代器可以产生下一个值,则为 false。
        如果迭代器已将序列迭代完毕,则为 true。
    value
        迭代器返回的任何 JavaScript 值。done 为 true 时可省略。

return():for-of提前退出调用,返回{ done: true }
throw():不使用,配合 Generator 函数使用

迭代对象

可被迭代的对象 - 实现了[Symbol.iterator]方法。

原生具备 Iterator 接口的数据结构如下。

  • Array
  • Map
  • Set
  • String
  • TypedArray
  • 函数的 arguments 对象
  • NodeList 对象

迭代语句

for...in:以原始插入的顺序迭代对象的可枚举属性
for...of:根据迭代对象的迭代器实现迭代数据 实质调用迭代对象的`Symbol.iterator`方法

迭代器实现原理

obj[Symbol.iterator] = function () {
  return {
    next() {
      return {
        value: this.i++,
        done: false,
      };
    },
  };
};

对象(Object)之所以没有默认部署 Iterator 接口,是因为对象的哪个属性先遍历,哪个属性后遍历是不确定的,需要开发者手动指定

调用 Iterator 的场景

  1. 解构赋值

  2. 扩展运算符

  3. yield*

  4. 接收数组的地方

    • for…of
    • Array.from()
    • Map(), Set(), WeakMap(), WeakSet()
    • Promise.all()
    • Promise.race()

Generator

基本概念

  • 形式:Generator 是一个普通函数,两个特征
    • function 命令与函数名之间有一个星号
    • 函数体内部使用 yield 语句,定义遍历器的每个成员,即不同的内部状态
  • 解读:每次调用 next方法,内部指针就从函数头部或上一次停下来的地方开始执行,直到遇到下一个 yield表达式(或 return语句)为止。
function* fn() {
  yield 1;
  yield 2;
  yield 3;
}

let g = gen();

应用场景

  • 异步操作的同步化表达
  • 控制流管理
  • 部署 Iterator 接口
  • 作为有 Iterator 接口的数据结构

ESModule

export 命令

  • 默认导出:export default XXX
  • 单独导出:export const name = “Abc”
  • 按需导出:export { name, sex, age }(推荐)
  • 改名导出:export { name as exportName }

export 可以导出多个,export default 只能导出一个

import 命令

  • 默认导入:import module from “fileName”
  • 整体导入:import * as module from “fileName”
  • 按需导入:import { name, sex, age } from “fileName”
  • 改名导入:import { name as importName } from “fileName”
  • 自执导入:import “fileName”
  • 复合导入:import module, { name } from “fileName”
    • 默认导入在前 按需导入在后

导入 export 导出的,命名要保持一致,导入 export default 导出的,命名可以自定义

模块化优点

  • 防止作用域污染
  • 提高代码的复用性
  • 维护成本降低

模块化方案

  • CommonJS:用于服务器(动态化依赖)
  • AMD:用于浏览器(动态化依赖)
  • CMD:用于浏览器(动态化依赖)
  • UMD:用于浏览器和服务器(动态化依赖)
  • ESM:用于浏览器和服务器(静态化依赖)

ES6 模块与 CommonJS 模块的差异

  • CommonJS 模块输出的是一个值的拷贝,ES6 模块输出的是值的引用。
  • CommonJS 模块是运行时加载,ES6 模块是编译时输出接口。
  • CommonJS 模块的 require()同步加载模块,ES6 模块的 import命令是异步加载,有一个独立的模块依赖的解析阶段。

Proxy

概括

Proxy 用于修改某些操作的默认行为,等同于在语言层面做出修改,所以属于一种“元编程”(meta programming),即对编程语言进行编程。

ES6 原生提供 Proxy 构造函数,用来生成 Proxy 实例。

var proxy = new Proxy(target, handler);

Proxy 对象的所有用法,都是上面这种形式,不同的只是 handler参数的写法。

  • new Proxy()表示生成一个 Proxy实例
  • target参数表示所要拦截的目标对象
  • handler参数也是一个对象,用来定制拦截行为。

实例方法

  • get(target, propKey, receiver):拦截对象属性的读取,比如 proxy.fooproxy['foo']
  • set(target, propKey, value, receiver):拦截对象属性的设置,比如 proxy.foo = vproxy['foo'] = v,返回一个布尔值。
  • has(target, propKey):拦截 propKey in proxy的操作,返回一个布尔值。
  • deleteProperty(target, propKey):拦截 delete proxy[propKey]的操作,返回一个布尔值。
  • ownKeys(target):拦截 Object.getOwnPropertyNames(proxy)Object.getOwnPropertySymbols(proxy)Object.keys(proxy)for...in循环,返回一个数组。该方法返回目标对象所有自身的属性的属性名,而 Object.keys()的返回结果仅包括目标对象自身的可遍历属性。
  • getOwnPropertyDescriptor(target, propKey):拦截 Object.getOwnPropertyDescriptor(proxy, propKey),返回属性的描述对象。
  • defineProperty(target, propKey, propDesc):拦截 Object.defineProperty(proxy, propKey, propDesc)Object.defineProperties(proxy, propDescs),返回一个布尔值。
  • preventExtensions(target):拦截 Object.preventExtensions(proxy),返回一个布尔值。
  • getPrototypeOf(target):拦截 Object.getPrototypeOf(proxy),返回一个对象。
  • isExtensible(target):拦截 Object.isExtensible(proxy),返回一个布尔值。
  • setPrototypeOf(target, proto):拦截 Object.setPrototypeOf(proxy, proto),返回一个布尔值。如果目标对象是函数,那么还有两种额外操作可以拦截。
  • apply(target, object, args):拦截 Proxy 实例作为函数调用的操作,比如 proxy(...args)proxy.call(object, ...args)proxy.apply(...)
  • construct(target, args):拦截 Proxy 实例作为构造函数调用的操作,比如 new proxy(...args)

this 问题

在 Proxy 代理的情况下,目标对象内部的 this关键字会指向 Proxy 代理。

Reflect

概述

提供拦截 JavaScript 操作的方法。

Reflect 不是一个函数对象,因此它是不可构造的。

静态方法

  • Reflect.apply(target, thisArg, args)
  • Reflect.construct(target, args)
  • Reflect.get(target, name, receiver)
  • Reflect.set(target, name, value, receiver)
  • Reflect.defineProperty(target, name, desc)
  • Reflect.deleteProperty(target, name)
  • Reflect.has(target, name)
  • Reflect.ownKeys(target)
  • Reflect.isExtensible(target)
  • Reflect.preventExtensions(target)
  • Reflect.getOwnPropertyDescriptor(target, name)
  • Reflect.getPrototypeOf(target)
  • Reflect.setPrototypeOf(target, prototype)

ES8

Async

概述

定义:Generator 函数语法糖
原理:将 Generator 函数和自动执行器 spawn 包装在一个函数里
形式:将 Generator 函数的*替换成 async,将 yield 替换成 await
作用:将异步以同步的形式书写
async函数的语法规则总体上比较简单,难点是错误处理机制。

语法
返回 Promise 对象

async函数返回一个 Promise 对象。
async函数内部 return语句返回的值,会成为 then方法回调函数的参数。
async函数内部抛出错误,会导致返回的 Promise 对象变为 reject状态。抛出的错误对象会被 catch方法回调函数接收到。

Promise 对象的状态变化

async函数返回的 Promise 对象,必须等到内部所有 await命令后面的 Promise 对象执行完,才会发生状态改变,除非遇到 return语句或者抛出错误。

只有 async函数内部的异步操作执行完,才会执行 then方法指定的回调函数。

错误处理

如果 await后面的异步操作出错,那么等同于 async函数返回的 Promise 对象被 reject

await 命令

正常情况下,await命令后面是一个 Promise 对象,返回该对象的结果。
如果不是 Promise 对象,就直接返回对应的值。

使用注意点
  1. await命令后面的 Promise对象,运行结果可能是 rejected,所以最好把 await命令放在 try...catch代码块中。
  2. 多个 await命令后面的异步操作,如果不存在继发关系,最好让它们同时触发。
  3. await命令只能用在 async函数之中,如果用在普通函数,就会报错。(ES13 应该可以使用顶层 await 了)
Async 对 Generator 改进
  • 内置执行器
  • 更好的语义
  • 更广的适用性
  • 返回值是 Promise 对象

ES9

异步遍历器

语法特点

调用遍历器的 next方法,返回的是一个 Promise 对象。

await 可以和 for…of 循环一起使用,以串行的方式运行异步操作

Promise.prototype.finally(onFinally)

参数:onFinally Promise 结束后调用的 Function。
返回值:返回一个设置了 finally 回调函数的 Promise 对象。

finally() 方法返回一个 Promise。
promise 结束时,无论结果是 fulfilled 或者是 rejected,都会执行指定的回调函数。

避免了同样的语句需要在 then()和 catch()中各写一次的情况。

ES11

Promise.allSettled(iterable)

参数:iterable 一个可迭代的对象,例如 Array,其中每个成员都是 Promise
返回一个在所有给定的 promise 都已经 fulfilledrejected 后的 promise,并带有一个对象数组,每个对象表示对应的 promise 结果。
简单地说,就是当所有 promise 返回后,无论成功或失败都会返回结果数组。

使用场景比较
  • Promise.allSettled 返回的结果相互不依赖;
  • Promise.all() 更适合彼此相互依赖或者在其中任何一个 reject 时立即结束。

ES12

Promise.any(iterable)

参数:iterable 一个可迭代的对象,例如 Array。
返回值:
接收一个 Promise 可迭代对象,只要其中的一个 promise 成功,就返回那个已经成功的 promise。全为 reject,即返回 reject 状态。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值