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加载
背景:CommonJS
和ESM
互不兼容,目前解决方案是将两者分开,采用各自的加载方案
区分:要求ESM采用 .mjs
后缀文件名
require()
不能加载.mjs文件
,只有import命令
才可加载.mjs文件
.mjs文件
里不能使用require()
,必须使用import命令
加载文件
驱动:node --experimental-modules file.mjs
限制:Node的import命令
目前只支持加载本地模块(file:协议
),不支持加载远程模块
加载优先级
- 脚本文件省略后缀名:依次尝试加载四个后缀名文件(
.mjs
、.js
、.json
、node
) - 以上不存在:尝试加载
package.json
的main字段
指定的脚本 - 以上不存在:依次尝试加载名称为
index
四个后缀名文件(.mjs
、.js
、.json
、node
) - 以上不存在:报错
不存在的内部变量:arguments
、exports
、module
、require
、this
、__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);
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);
2
3
4
# Iterator
定义:为各种不同的数据结构提供统一的访问机制
原理:创建一个指针指向首个成员,按照次序使用next()
指向下一个成员,直接到结束位置(数据结构只要部署Iterator接口
就可完成遍历操作)
作用
- 为各种数据结构提供一个统一的简便的访问接口
- 使得数据结构成员能够按某种次序排列
- ES6创造了新的遍历命令
for-of
,Iterator接口
主要供for-of
消费
形式:for-of
(自动去寻找Iterator接口)
数据结构
- 集合:
Array
、Object
、Set
、Map
- 原生具备接口的数据结构:
String
、Array
、Set
、Map
、TypedArray
、Arguments
、NodeList
部署:默认部署在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()
转换)
计算生成数据结构: Array
、Set
、 Map
- keys():返回遍历器对象,遍历所有的键
- values():返回遍历器对象,遍历所有的值
- entries():返回遍历器对象,遍历所有的键值对
与 for-in
区别
- 有着同
for-in
一样的简洁语法,但没有for-in
那些缺点 - 不同于
forEach()
,它可与break
、continue
和return
配合使用 - 提供遍历所有数据结构的统一操作接口
# 应用场景
- 改写具有
Iterator接口
的数据结构的Symbol.iterator
- 解构赋值:对Set进行结构
- 扩展运算符:将部署
Iterator接口
的数据结构转为数组 - yield*:
yield*
后跟一个可遍历的数据结构,会调用其遍历器接口 - 接受数组作为参数的函数:
for-of
、Array.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
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
虽然因为await
让for-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
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毫秒后我成功啦!!!
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# Array.flatMap
现在给你一个需求
let arr = ["科比 詹姆斯 安东尼", "利拉德 罗斯 麦科勒姆"];
将上面数组转为
[ '科比', '詹姆斯', '安东尼', '利拉德', '罗斯', '麦科勒姆' ]
第一时间想到map + flat
console.log(arr.map(x => x.split(" ")).flat());
// [ '科比', '詹姆斯', '安东尼', '利拉德', '罗斯', '麦科勒姆' ]
2
flatMap
就是flat + map
,一个方法顶两个
console.log(arr.flatMap(x => x.split(" ")));
// [ '科比', '詹姆斯', '安东尼', '利拉德', '罗斯', '麦科勒姆' ]
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: '男' }
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: '男' }
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
- 不具有then()的对象:将此对象转为Promise对象并返回,状态为
Promise.reject():将对象转为状态为
rejected
的Promise对象(等价于new Promise((resolve, reject) => reject())
)
# 应用场景
- 加载图片
- AJAX转Promise对象
# 重点难点
- 只有异步操作的结果可决定当前状态是哪一种,其他操作都无法改变这个状态
- 状态改变只有两种可能:从
pending
变为resolved
、从pending
变为rejected
- 一旦新建
Promise对象
就会立即执行,无法中途取消 - 不设置回调函数,内部抛错不会反应到外部
- 当处于
pending
时,无法得知目前进展到哪一个阶段 - 实例状态变为
resolved
或rejected
时,会触发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语句
则返回对象的value
为undefined
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语句
- next():将
# 应用场景
- 异步操作同步化表达
- 控制流管理
- 为对象部署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()
返回对象的done
为true
,for-of
遍历会中止且不包含该返回对象 - 函数内部部署
try-finally
且正在执行try
,那么return()
会导致立刻进入finally
,执行完finally
以后整个函数才会结束 - 函数内部没有部署
try-catch
,throw()
抛错将被外部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");
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
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();// 开始处理过程
}
2
3
4
5
6
7
8
9
10
11
12
13
# ES2016
# 数值扩展
- 指数运算符(**):数值求幂(相当于
Math.pow()
)
# 数组扩展
- includes():是否存在指定成员
# ES2017
# 声明
- 共享内存和原子操作:由全局对象
SharedArrayBuffer
和Atomics
实现,将数据存储在一块共享内存空间中,这些数据可在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-of
和Promise.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
且不再往下执行) - 空判断操作符(??):是否值为
undefined
或null
,是则使用默认值
# 函数扩展
- 函数部分执行:复用函数功能(
?
表示单个参数占位符,...
表示多个参数占位符) - 管道操作符(|>):把左边表达式的值传入右边的函数进行求值(
f(x)
=>x |> f
) - 绑定运算符(:😃 :函数绑定(左边是对象右边是函数,取代
bind
、apply
、call
调用)- bind:
bar.bind(foo)
=>foo::bar
- apply:
bar.apply(foo, arguments)
=>foo::bar(...arguments)
- bind:
# 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