es6之module,iterator,promise及es6+

# Module

# 命令

  • export:规定模块对外接口
    • 默认导出export default Person(导入时可指定模块任意名称,无需知晓内部真实名称)
    • 单独导出export const name = "Bruce"
    • 按需导出export { age, name, sex }(推荐)
    • 改名导出export { name as newName }
  • import:导入模块内部功能
    • 默认导入import Person from "person"
    • 整体导入import * as Person from "person"
    • 按需导入import { age, name, sex } from "person"
    • 改名导入import { name as newName } from "person"
    • 自执导入import "person"
    • 复合导入import Person, { name } from "person"
  • 复合模式export命令import命令结合在一起写成一行,变量实质没有被导入当前模块,相当于对外转发接口,导致当前模块无法直接使用其导入变量
    • 默认导入导出export { default } from "person"
    • 整体导入导出export * from "person"
    • 按需导入导出export { age, name, sex } from "person"
    • 改名导入导出export { name as newName } from "person"
    • 具名改默认导入导出export { name as default } from "person"
    • 默认改具名导入导出export { default as name } from "person"

继承:默认导出改名导出结合使用可使模块具备继承性

设计思想:尽量地静态化,使得编译时就能确定模块的依赖关系,以及输入和输出的变量

严格模式:ES6模块自动采用严格模式(不管模块头部是否添加use strict)

# 模块方案

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

# 加载方式

  • 运行时加载
    • 定义:整体加载模块生成一个对象,再从对象上获取需要的属性和方法进行加载(全部加载)
    • 影响:只有运行时才能得到这个对象,导致无法在编译时做静态优化
  • 编译时加载
    • 定义:直接从模块中获取需要的属性和方法进行加载(按需加载)
    • 影响:在编译时就完成模块加载,效率比其他方案高,但无法引用模块本身(本身不是对象),可拓展JS高级语法(宏和类型校验)

# 加载实现

  • 传统加载:通过 <script>进行同步或异步加载脚本
    • 同步加载:<script src=""></script>
    • Defer异步加载:<script src="" defer></script>(顺序加载,渲染完再执行)
    • Async异步加载:<script src="" async></script>(乱序加载,下载完就执行)
  • 模块加载<script type="module" src=""></script>(默认是Defer异步加载)

# CommonJS和ESM的区别

CommonJS输出值的拷贝ESM输出值的引用

  • CommonJS一旦输出一个值,模块内部的变化就影响不到这个值
  • ESM是动态引用且不会缓存值,模块里的变量绑定其所在的模块,等到脚本真正执行时,再根据这个只读引用到被加载的那个模块里去取值

CommonJS是运行时加载,ESM是编译时加载

  • CommonJS加载模块是对象(即module.exports),该对象只有在脚本运行完才会生成
  • ESM加载模块不是对象,它的对外接口只是一种静态定义,在代码静态解析阶段就会生成

# Node加载

背景:CommonJSESM互不兼容,目前解决方案是将两者分开,采用各自的加载方案

区分:要求ESM采用 .mjs后缀文件名

  • require()不能加载.mjs文件,只有import命令才可加载.mjs文件
  • .mjs文件里不能使用require(),必须使用import命令加载文件

驱动:node --experimental-modules file.mjs

限制:Node的import命令目前只支持加载本地模块(file:协议),不支持加载远程模块

加载优先级

  • 脚本文件省略后缀名:依次尝试加载四个后缀名文件(.mjs.js.jsonnode)
  • 以上不存在:尝试加载package.jsonmain字段指定的脚本
  • 以上不存在:依次尝试加载名称为index四个后缀名文件(.mjs.js.jsonnode)
  • 以上不存在:报错

不存在的内部变量:argumentsexportsmodulerequirethis__dirname__filename

CommonJS加载ESM

  • 不能使用require(),只能使用import()

ESM加载CommonJS

  • 自动将module.exports转化成export default
  • CommonJS输出缓存机制在ESM加载方式下依然有效
  • 采用import命令加载CommonJS模块时,不允许采用按需导入,应使用默认导入整体导入

# 循环加载

定义:脚本A的执行依赖脚本B,而脚本A的执行又依赖脚本B

加载原理

  • CommonJS:require()首次加载脚本就会执行整个脚本,在内存里生成一个对象缓存下来,二次加载脚本时直接从缓存中获取
  • ESM:import命令加载变量不会被缓存,而是成为一个指向被加载模块的引用

循环加载

  • CommonJS:只输出已经执行的部分,还未执行的部分不会输出
  • ESM:需开发者自己保证真正取值时能够取到值 (可把变量写成函数形式,函数具有提升作用)

# 重点难点

  • ES6模块中,顶层this指向undefined,不应该在顶层代码使用this
  • 一个模块就是一个独立的文件,该文件内部的所有变量,外部无法获取
  • export命令输出的接口与其对应的值是动态绑定关系,即通过该接口可获取模块内部实时的值
  • import命令大括号里的变量名必须与被导入模块对外接口的名称相同
  • import命令输入的变量只读(本质是输入接口),不允许在加载模块的脚本里改写接口
  • import命令命令具有提升效果,会提升到整个模块的头部,首先执行
  • 重复执行同一句import语句,只会执行一次
  • export default命令只能使用一次
  • export default命令导出的整体模块,在执行import命令时其后不能跟大括号
  • export default命令本质是输出一个名为default的变量,后面不能跟变量声明语句
  • export default命令本质是将后面的值赋给名为default的变量,可直接将值写在其后
  • export default命令export {}命令可同时存在,对应复合导入
  • export命令import命令可出现在模块任何位置,只要处于模块顶层即可,不能处于块级作用域
  • import()加载模块成功后,此模块会作为一个对象,当作then()的参数,可使用对象解构赋值来获取输出接口
  • 同时动态加载多个模块时,可使用Promise.all()import()相结合来实现
  • import()和结合async/await来书写同步操作的代码

单例模式:跨模块常量

// 常量跨文件共享
// person.js
const NAME = "Bruce";
const AGE = 25;
const SEX = "male";
export { AGE, NAME, SEX };
// file1.js
import { AGE } from "person";
console.log(AGE);
// file2.js
import { AGE, NAME, SEX } from "person";
console.log(AGE, NAME, SEX);
1
2
3
4
5
6
7
8
9
10
11
12

默认导入互换整体导入

import Person from "person";
console.log(Person.AGE);
import * as Person from "person";
console.log(Person.default.AGE);
1
2
3
4

# Iterator

定义:为各种不同的数据结构提供统一的访问机制

原理:创建一个指针指向首个成员,按照次序使用next()指向下一个成员,直接到结束位置(数据结构只要部署Iterator接口就可完成遍历操作)

作用

  • 为各种数据结构提供一个统一的简便的访问接口
  • 使得数据结构成员能够按某种次序排列
  • ES6创造了新的遍历命令for-ofIterator接口主要供for-of消费

形式:for-of(自动去寻找Iterator接口)

数据结构

  • 集合:ArrayObjectSetMap
  • 原生具备接口的数据结构:StringArraySetMapTypedArrayArgumentsNodeList

部署:默认部署在Symbol.iterator(具备此属性被认为可遍历的iterable)

遍历器对象

  • next():下一步操作,返回{ done, value }(必须部署)
  • return()for-of提前退出调用,返回{ done: true }
  • throw():不使用,配合Generator函数使用

# ForOf循环

定义:调用Iterator接口产生遍历器对象(for-of内部调用数据结构的Symbol.iterator())

遍历字符串:for-in获取索引for-of获取(可识别32位UTF-16字符)

遍历数组:for-in获取索引for-of获取

遍历对象:for-in获取for-of需自行部署

遍历Set:for-of获取 => for (const v of set)

遍历Map:for-of获取键值对 => for (const [k, v] of map)

遍历类数组:包含length的对象Arguments对象NodeList对象(无Iterator接口的类数组可用Array.from()转换)

计算生成数据结构ArraySetMap

  • keys():返回遍历器对象,遍历所有的键
  • values():返回遍历器对象,遍历所有的值
  • entries():返回遍历器对象,遍历所有的键值对

for-in区别

  • 有着同for-in一样的简洁语法,但没有for-in那些缺点
  • 不同于forEach()它可与breakcontinuereturn配合使用
  • 提供遍历所有数据结构的统一操作接口

# 应用场景

  • 改写具有Iterator接口的数据结构的Symbol.iterator
  • 解构赋值:对Set进行结构
  • 扩展运算符:将部署Iterator接口的数据结构转为数组
  • yield*:yield*后跟一个可遍历的数据结构,会调用其遍历器接口
  • 接受数组作为参数的函数:for-ofArray.from()new Set()new WeakSet()new Map()new WeakMap()Promise.all()Promise.race()

# for await of

# for-of和for await of的区别

  • for-of是用来遍历同步操作的;
  • for-of里面用await,如果有其他操作,也会有输出顺序错误;
  • for await of 是可以对异步集合进行操作;

案例:

function Gen(time) {
  return new Promise((resolve, reject) => {
    setTimeout(function () {
      resolve(time)
    },time)
  })
}

async function test() {
  let arr = [Gen(2000), Gen(1000), Gen(3000)]
  for(let item of arr) {
    console.log(Date.now(), await item.then(console.log))
  }
}

test()

// 2000
// 1597047766221 undefined
// 1000
// 1597047768223 undefined
// 3000
// 1597047768224 undefined
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

分析输出结果:先执行了await后面的then,返回2000之后 执行console.log返回时间戳 然后await的返回值是空,所以返回undefined 虽然因为awaitfor-of暂停了,但是执行的顺序和我们想要的还是不一样

最终的解决方式 —— For await of

test函数前面还要添加async关键字,对for-of进行改进

function Gen(time) {
  return new Promise((resolve, reject) => {
    setTimeout(function () {
      resolve(time)
    },time)
  })
}

async function test() {
  let arr = [Gen(2000), Gen(100), Gen(3000)]
  for await(let item of arr) {
    console.log(Date.now(), item)
  }
}

test()

// 1597048677429 2000
// 1597048677429 100
// 1597048678429 3000
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

遍历 await使用;

function fn (time) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve(`${time}毫秒后我成功啦!!!`)
    }, time)
  })
}

async function asyncFn () {
  const arr = [fn(3000), fn(1000), fn(1000), fn(2000), fn(500)]
  for await (let x of arr) {
    console.log(x)
  }
}

asyncFn()
//3000毫秒后我成功啦!!!
//1000毫秒后我成功啦!!!
//1000毫秒后我成功啦!!!
//2000毫秒后我成功啦!!!
//500毫秒后我成功啦!!!
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

# Array.flatMap

现在给你一个需求

let arr = ["科比 詹姆斯 安东尼", "利拉德 罗斯 麦科勒姆"];
1

将上面数组转为

[ '科比', '詹姆斯', '安东尼', '利拉德', '罗斯', '麦科勒姆' ]
1

第一时间想到map + flat

console.log(arr.map(x => x.split(" ")).flat());
// [ '科比', '詹姆斯', '安东尼', '利拉德', '罗斯', '麦科勒姆' ]
1
2

flatMap就是flat + map,一个方法顶两个

console.log(arr.flatMap(x => x.split(" ")));
// [ '科比', '詹姆斯', '安东尼', '利拉德', '罗斯', '麦科勒姆' ]
1
2

# Object.fromEntries

前面ES8的Object.entries是把对象转成键值对数组,而Object.fromEntries则相反,是把键值对数组转为对象

const arr = [
  ['name', 'samy'],
  ['age', 22],
  ['gender', '男']
]
console.log(Object.fromEntries(arr)) // { name: 'samy', age: 22, gender: '男' }
1
2
3
4
5
6

他还有一个用处,就是把Map转为对象

const map = new Map()
map.set('name', 'samy')
map.set('age', 22)
map.set('gender', '男')

console.log(map) // Map(3) { 'name' => 'samy', 'age' => 22, 'gender' => '男' }

const obj = Object.fromEntries(map)
console.log(obj) // { name: 'samy', age: 22, gender: '男' }
1
2
3
4
5
6
7
8
9

# Promise

定义:包含异步操作结果的对象

状态

  • 进行中pending
  • 已成功resolved
  • 已失败rejected

特点

  • 对象的状态不受外界影响
  • 一旦状态改变就不会再变,任何时候都可得到这个结果

声明:new Promise((resolve, reject) => {})

出参

  • resolve:将状态从未完成变为成功,在异步操作成功时调用,并将异步操作的结果作为参数传递出去
  • reject:将状态从未完成变为失败,在异步操作失败时调用,并将异步操作的错误作为参数传递出去

# 方法

  • then():分别指定 resolved状态rejected状态的回调函数

    • 第一参数:状态变为resolved时调用
  • 第二参数:状态变为rejected时调用(可选)

  • catch():指定发生错误时的回调函数

  • Promise.all():将多个实例包装成一个新实例,返回全部实例状态变更后的结果数组(齐变更再返回)

    • 入参:具有Iterator接口的数据结构
  • 成功:只有全部实例状态变成resolved,最终状态才会变成resolved

    • 失败:其中一个实例状态变成rejected,最终状态就会变成rejected
  • Promise.race():将多个实例包装成一个新实例,返回全部实例状态优先变更后的结果(先变更先返回)

  • Promise.resolve():将对象转为Promise对象(等价于 new Promise(resolve => resolve()))

    • Promise实例:原封不动地返回入参
  • Thenable对象:将此对象转为Promise对象并返回(Thenable为包含then()的对象,执行then()相当于执行此对象的then())

    • 不具有then()的对象:将此对象转为Promise对象并返回,状态为resolved
    • 不带参数:返回Promise对象,状态为resolved
  • Promise.reject():将对象转为状态为rejected的Promise对象(等价于new Promise((resolve, reject) => reject()))

# 应用场景

  • 加载图片
  • AJAX转Promise对象

# 重点难点

  • 只有异步操作的结果可决定当前状态是哪一种,其他操作都无法改变这个状态
  • 状态改变只有两种可能:从pending变为resolved、从pending变为rejected
  • 一旦新建Promise对象就会立即执行,无法中途取消
  • 不设置回调函数,内部抛错不会反应到外部
  • 当处于pending时,无法得知目前进展到哪一个阶段
  • 实例状态变为resolvedrejected时,会触发then()绑定的回调函数
  • resolve()reject()的执行总是晚于本轮循环的同步任务
  • then()返回新实例,其后可再调用另一个then()
  • then()运行中抛出错误会被catch()捕获
  • reject()的作用等同于抛出错误
  • 实例状态已变成resolved时,再抛出错误是无效的,不会被捕获,等于没有抛出
  • 实例状态的错误具有冒泡性质,会一直向后传递直到被捕获为止,错误总是会被下一个catch()捕获
  • 不要在then()里定义rejected状态的回调函数(不使用其第二参数)
  • 建议使用catch()捕获错误,不要使用then()第二个参数捕获
  • 没有使用catch()捕获错误,实例抛错不会传递到外层代码,即不会有任何反应
  • 作为参数的实例定义了catch(),一旦被rejected并不会触发Promise.all()catch()
  • Promise.reject()的参数会原封不动地作为rejected的理由,变成后续方法的参数

# Generator

封装多个内部状态的异步编程解决方案; 生成器(generators)是一个能返回一个迭代器的函数。 生成器函数也是一种函数,最直观的表现就是比普通的function多了个星号*,在其函数体内可以使用yield关键字,有意思的是函数会在每个yield后停顿。

形式:调用Generator函数(该函数不执行)返回指向内部状态的指针对象(不是运行结果)

声明:function* Func() {}

方法

  • next():使指针移向下一个状态,返回{ done, value }(入参会被当作上一个yield命令表达式的返回值)
  • return():返回指定值且终结遍历Generator函数,返回{ done: true, value: 入参 }
  • throw():在Generator函数体外抛出错误,在Generator函数体内捕获错误,返回自定义的new Errow()

yield命令:声明内部状态的值( return声明结束返回的值)

  • 遇到yield命令就暂停执行后面的操作,并将其后表达式的值作为返回对象的value
  • 下次调用next()时,再继续往下执行直到遇到下一个yield命令
  • 没有再遇到yield命令就一直运行到Generator函数结束,直到遇到return语句为止并将其后表达式的值作为返回对象的value
  • Generator函数没有return语句则返回对象的valueundefined

yield*命令:在一个Generator函数里执行另一个Generator函数(后随具有Iterator接口的数据结构)

遍历:通过for-of自动调用next()

作为对象属性

  • 全写:const obj = { method: function*() {} }
  • 简写:const obj = { * method() {} }

上下文:执行产生的上下文环境一旦遇到yield命令就会暂时退出堆栈(但并不消失),所有变量和对象会冻结在当前状态,等到对它执行next()时,这个上下文环境又会重新加入调用栈,冻结的变量和对象恢复执行

# 方法异同

  • 相同点:next()throw()return()本质上是同一件事,作用都是让函数恢复执行且使用不同的语句替换yield命令
  • 不同点
    • next():将yield命令替换成一个
    • return():将yield命令替换成一个return语句
    • throw():将yield命令替换成一个throw语句

# 应用场景

  • 异步操作同步化表达
  • 控制流管理
  • 为对象部署Iterator接口:把Generator函数赋值给对象的Symbol.iterator,从而使该对象具有Iterator接口
  • 作为具有Iterator接口的数据结构

# 重点难点

  • 每次调用next(),指针就从函数头部上次停下的位置开始执行,直到遇到下一个yield命令return语句为止
  • 函数内部可不用yield命令,但会变成单纯的暂缓执行函数(还是需要next()触发)
  • yield命令是暂停执行的标记,next()是恢复执行的操作
  • yield命令用在另一个表达式中必须放在圆括号
  • yield命令用作函数参数或放在赋值表达式的右边,可不加圆括号
  • yield命令本身没有返回值,可认为是返回undefined
  • yield命令表达式为惰性求值,等next()执行到此才求值
  • 函数调用后生成遍历器对象,此对象的Symbol.iterator是此对象本身
  • 在函数运行的不同阶段,通过next()从外部向内部注入不同的值,从而调整函数行为
  • 首个next()用来启动遍历器对象,后续才可传递参数
  • 想首次调用next()时就能输入值,可在函数外面再包一层
  • 一旦next()返回对象的donetruefor-of遍历会中止且不包含该返回对象
  • 函数内部部署try-finally且正在执行try,那么return()会导致立刻进入finally,执行完finally以后整个函数才会结束
  • 函数内部没有部署try-catchthrow()抛错将被外部try-catch捕获
  • throw()抛错要被内部捕获,前提是必须至少执行过一次next()
  • throw()被捕获以后,会附带执行下一条yield命令
  • 函数还未开始执行,这时throw()抛错只可能抛出在函数外部

首次next()可传值

function Wrapper(func) {
    return function(...args) {
        const generator = func(...args);
        generator.next();
        return generator;
    }
}
const print = Wrapper(function*() {
    console.log(`First Input: ${yield}`);
    return "done";
});
print().next("hello");
1
2
3
4
5
6
7
8
9
10
11
12
function *createIterator() {// 生成器
  yield 1;
  yield 2;
  yield 3;
}
let iterator = createIterator();// 生成器能像正规函数那样被调用,但会返回一个迭代器
console.log(iterator.next().value); // 1
console.log(iterator.next().value); // 2
console.log(iterator.next().value); // 3
1
2
3
4
5
6
7
8
9
//需要一个能够调用生成器并启动迭代器的方法
function run(taskDef) {
  // taskDef 即一个生成器函数; 创建迭代器,让它在别处可用
  let task = taskDef();
  let result = task.next();// 启动任务
  function step() {// 递归使用函数来保持对 next() 的调用
    if (!result.done) { // 如果还有更多要做的
      result = task.next();
      step();
    }
  }
  step();// 开始处理过程
}
1
2
3
4
5
6
7
8
9
10
11
12
13

# ES2016

# 数值扩展

  • 指数运算符(**):数值求幂(相当于Math.pow())

# 数组扩展

  • includes():是否存在指定成员

# ES2017

# 声明

  • 共享内存和原子操作:由全局对象SharedArrayBufferAtomics实现,将数据存储在一块共享内存空间中,这些数据可在JS主线程web-worker线程之间共享

# 字符串扩展

  • padStart():把指定字符串填充到字符串头部,返回新字符串
  • padEnd():把指定字符串填充到字符串尾部,返回新字符串

# 对象扩展

  • Object.getOwnPropertyDescriptors():返回对象所有自身属性(非继承属性)的描述对象
  • Object.values():返回以值组成的数组
  • Object.entries():返回以键和值组成的数组

# 函数扩展

  • 函数参数尾逗号:允许函数最后一个参数有尾逗号

# Async

定义:使异步函数以同步函数的形式书写(Generator函数语法糖)

原理:将Generator函数和自动执行器spawn包装在一个函数里

形式:将Generator函数*替换成async,将yield替换成await

声明

  • 具名函数:async function Func() {}
  • 函数表达式:const func = async function() {}
  • 箭头函数:const func = async() => {}
  • 对象方法:const obj = { async func() {} }
  • 类方法:class Cla { async Func() {} }

await命令:等待当前Promise对象状态变更完毕

  • 正常情况:后面是Promise对象则返回其结果,否则返回对应的值
  • 后随Thenable对象:将其等同于Promise对象返回其结果

错误处理:将await命令Promise对象放到try-catch中(可放多个)

# Async对Generator改进

  • 内置执行器
  • 更好的语义
  • 更广的适用性
  • 返回值是Promise对象

# 应用场景

  • 按顺序完成异步操作

# 重点难点

  • Async函数返回Promise对象,可使用then()添加回调函数
  • 内部return返回值会成为后续then()的出参
  • 内部抛出错误会导致返回的Promise对象变为rejected状态,被catch()接收到
  • 返回的Promise对象必须等到内部所有await命令Promise对象执行完才会发生状态改变,除非遇到return语句抛出错误
  • 任何一个await命令Promise对象变为rejected状态,整个Async函数都会中断执行
  • 希望即使前一个异步操作失败也不要中断后面的异步操作
    • await命令Promise对象放到try-catch
    • await命令Promise对象跟一个catch()
  • await命令Promise对象可能变为rejected状态,最好把其放到try-catch
  • 多个await命令Promise对象若不存在继发关系,最好让它们同时触发
  • await命令只能用在Async函数之中,否则会报错
  • 数组使用forEach()执行async/await会失效,可使用for-ofPromise.all()代替
  • 可保留运行堆栈,函数上下文随着Async函数的执行而存在,执行完成就消失

# ES2018

# 字符串扩展

  • 放松对标签模板里字符串转义的限制:遇到不合法的字符串转义返回undefined,并且从raw上可获取原字符串

# 对象扩展

  • 扩展运算符(...):转换对象为用逗号分隔的参数序列({ ...obj },相当于rest/spread参数的逆运算)

# 扩展应用

  • 克隆对象:const obj = { __proto__: Object.getPrototypeOf(obj1), ...obj1 }
  • 合并对象:const obj = { ...obj1, ...obj2 }
  • 转换字符串为对象:{ ..."hello" }
  • 转换数组为对象:{ ...[1, 2] }
  • 与对象解构赋值结合:const { x, ...rest/spread } = { x: 1, y: 2, z: 3 }(不能复制继承自原型对象的属性)
  • 修改现有对象部分属性:const obj = { x: 1, ...{ x: 2 } }

# 正则扩展

  • s修饰符:dotAll模式修饰符,使.匹配任意单个字符(dotAll模式)
  • dotAll:是否设置s修饰符
  • 后行断言x只有在y后才匹配
  • 后行否定断言x只有不在y后才匹配
  • Unicode属性转义:匹配符合 Unicode某种属性的所有字符
    • 正向匹配:\p{PropRule}
    • 反向匹配:\P{PropRule}
    • 限制:\p{...}\P{...}只对Unicode字符有效,使用时需加上u修饰符
  • 具名组匹配:为每组匹配指定名字( ?<GroupName>)
    • 形式:str.exec().groups.GroupName
    • 解构赋值替换
      • 声明:const time = "2017-09-11"const regexp = /(?\d{4})-(?\d{2})-(?\d{2})/u
      • 匹配:time.replace(regexp, "$/$/$")

# Promise

  • finally():指定不管最后状态如何都会执行的回调函数

# Async

  • 异步迭代器(for-await-of):,循环等待每个Promise对象变为resolved状态才进入下一步

# ES2019

# 字符串扩展

  • 直接输入U+2028和U+2029:字符串可直接输入行分隔符段分隔符
  • JSON.stringify()改造:可返回不符合UTF-8标准的字符串
  • trimStart():消除字符串头部空格,返回新字符串
  • trimEnd():消除字符串尾部空格,返回新字符串

# 对象扩展

  • Object.fromEntries():返回以键和值组成的对象(Object.entries()的逆操作)

# 数组扩展

  • flat():扁平化数组,返回新数组
  • flatMap():映射且扁平化数组,返回新数组(只能展开一层数组)

# 函数扩展

  • toString()改造:返回函数原始代码(与编码一致)
  • catch()参数可省略catch()中的参数可省略

# Symbol

  • description:返回Symbol值的描述

# ES提案

# 声明

  • globalThis对象:作为顶层对象,指向全局环境下的this
  • do表达式:封装块级作用域的操作,返回内部最后执行表达式的值(do{})
  • throw表达式:直接使用throw new Error(),无需(){}包括
  • !#命令:指定脚本执行器(写在文件首行)

# 数值扩展

  • 数值分隔符(_):使用_作为千分位分隔符(增加数值的可读性)
  • BigInt():创建任何位数的整数(新增的数据类型,使用n结尾)

# 对象扩展

  • 链判断操作符(?.):是否存在对象属性(不存在返回undefined且不再往下执行)
  • 空判断操作符(??):是否值为undefinednull,是则使用默认值

# 函数扩展

  • 函数部分执行:复用函数功能(?表示单个参数占位符,...表示多个参数占位符)
  • 管道操作符(|>):把左边表达式的值传入右边的函数进行求值(f(x) => x |> f)
  • 绑定运算符(:😃 :函数绑定(左边是对象右边是函数,取代bindapplycall调用)
    • bind:bar.bind(foo) => foo::bar
    • apply:bar.apply(foo, arguments) => foo::bar(...arguments)

# Proxy

  • Promise.try():不想区分是否同步异步函数,包装函数为实例,使用then()指定下一步流程,使用catch()捕获错误

# Realm

  • 定义:提供沙箱功能,允许隔离代码,防止被隔离的代码拿到全局对象
  • 声明:new Realm().global

# Class

  • 静态属性:使用static定义属性,该属性不会被实例继承,只能通过类来调用
  • 私有属性:使用#定义属性,该属性只能在类内部访问
  • 私有方法:使用#定义方法,该方法只能在类内部访问
  • 装饰器:使用@注释或修改类和类方法

# Module

  • import():动态导入(返回 Promise )
    • 背景:import命令被JS引擎静态分析,先于模块内的其他语句执行,无法取代require()的动态加载功能,提案建议引入import()来代替require()
    • 位置:可在任何地方使用
    • 区别:require()同步加载import()异步加载
    • 场景:按需加载、条件加载、模块路径动态化
  • import.meta:返回脚本元信息

# Async

  • 顶层Await:允许在模块的顶层独立使用await命令(借用await解决模块异步加载的问题)

# 参考链接

https://es6.ruanyifeng.com/

https://juejin.im/post/5d9bf530518825427b27639d

上次更新: 2022/04/15, 05:41:26
×