ES2021
逻辑赋值运算符
类似于 += *= 等运算符:
??=&&=||=
let a = null
a ??= "flag" // a = a ?? "flag"
a &&= "flag" // a = a && "flag"
a ||= "falg" // a = a || "flag"
数字分隔符
允许在数字中间添加下划线 _ 增强可读性.
不允许出现在数字的首尾位置.
如: 1_000_000
注意: 带下划线的 String 类型的数字无法正常转换:
Number(1_000) // 1000
Number("1_000") // NaN
Promise.any()
接收一个 Promise 数组, 返回第一个 fulfilled 的 Promise 返回值.
当所有的 Promise 都 rejected 时, 进入 catch 块并返回 AggregateError 类型的错误.
对比 Promise.race() 是返回第一个 fulfilled 或 rejected 的 Promise 返回值.
String.replaceAll()
String.replace() 只替换第一次匹配的字符
WeakRefs 与 FinalizationRegistry
WeakRefs 为对象创建一个弱引用, 弱引用不会组织 JS 引擎垃圾回收期的回收, 一般很少使用.
使用 FinalizationRegistry 对象可以在垃圾回收器回收对象时, 执行回调函数:
// 构建监听对象被垃圾回收器清除的回调
const registry = new FinalizationRegistry(heldValue => {
console.log("----", heldValue)
})
const obj = {}
const token = {}
// 注册监听
registry.register(obj, "obj deleted!", token)
// 取消监听
// registry.unregister(token);
// 可能很久以后,回调执行
// ---- obj deleted!
ES 2020
链式判断运算符 ?.
支持 obj?.a?.b?.c 运算, 当中间某个属性为 null 或 undefined 时, 直接返回 undefined .
同时支持 obj?.[expr] 方括号形式与 fun?.(...args) 函数调用形式.
?? 运算符
类似于 || , 但只有运算符左侧值为 null 或 undefined 时才返回右侧值.
如 const username = list?.info?.base?.username ?? 'user';
而 || 运算符在左侧为 null undefined '' false 和 0 时都会返回右侧值.
import() 函数
之前的 import 只能用在模块顶层, 无法支持动态加载或条件导入模块.
import() 函数支持动态加载模块, 返回一个 Promise :
if (page === "home") {
import("./home.js")
.then(({ export1, export2 }) => {
// 加载成功
})
.catch(err => {
// 加载失败
})
}
适用于:
- 按需加载(如点击某按钮)
- 条件加载
- 动态的模块路径
export * as xx from "someModule"
相当于以下两个语句:
import * as xx from "someModule";export {xx};
BigInt 类型
可精确表示任意位数的整数, BigInt 类型的数据需要添加后缀 n .
const n = 34242345425325n
typeof n // "bigint"
// 作为构造函数
BigInt(3243) // 3243n
BigInt("324") // 324n
BigInt(false) // 0n
BigInt(true) // 1n
Promise.allSettled()
接收一组 Promise 实例作为参数, 当这些 Promise 都返回结果, 无论是 fulfilled 还是 rejected , 状态都会变为 fulfilled , 返回 [{ status: "fulfilled" | "rejected", value?: any, reason?: any }]
const resolved = Promise.resolve(42)
const rejected = Promise.reject(-1)
const allSettledPromise = Promise.allSettled([resolved, rejected])
allSettledPromise.then(function (results) {
console.log(results)
})
// [
// { status: 'fulfilled', value: 42 },
// { status: 'rejected', reason: -1 }
// ]
Promise.allSettled(), Promise.all(), Promise.race()
String.matchAll()
返回一个正则表达式在当前字符串中的所有匹配.
返回一个迭代器, 可以使用 for..of 遍历或使用 Array.from() 转为数组遍历.
let regex = /t(e)(st(\d?))/g
let string = "test1test2test3"
let r = string.matchAll(regex)
Array.from(r)
// [["test1", "e", "str1", "1"],
// ["test2", "e", "str2", "2"],
// ["test3", "e", "str3", "3"]]
globalThis
全局属性 globalThis 包含全局的 this 对象.
以前在不同环境下获取全局 this 对象的方法各不相同, 如:
- 在 Web 中通过
window或self获取this - 在 WebWorkers 中只能通过
self获取this - 在 Nodejs 中需要使用
global获取this
需要通过判断各种对象是否存在来获取 this, 较为繁琐.
globalThis 提供了一个标准方式来获取全局 this , 在各种环境下都适用.
for..in 定义了明确的顺序
for (x in y) 语句将以规定的顺序执行.
import.meta
返回带有 url 属性的对象, 可获取模块的基础 URL.
;<script type="module" src="module.js"></script>
console.log(import.meta) // { url: "file:///home/user/module.js" }
ES 2019
String.trimStart() / String.trimEnd()
单独去掉 String 头或尾部的空白字符.
Object.fromEntries()
即 Object.entries() 的逆过程, 将 [[key, value]] 形式的键值对转为对象结构:
let obj = { a: "aa", b: 40 }
let entries = Object.entries(obj)
entries // [["a", "aa"], ["b", 40]]
let obj1 = Object.fromEntries(entries)
obj1 // {a: "aa", b: 40}
Array.flat() / Array.flatMap()
-
Array.flat([depth = 1]) 按照指定深度展开/铺平数组, 默认深度为 1
const arr1 = [1, 2, [3, 4]] arr1.flat() // [1,2,3,4] const arr2 = [1, 2, [[[3, 4]]]] arr2.flat(2) // [1,2,[3,4]] arr2.flat(3) // [1,2,3,4] -
Array.flatMap() 即
Array.map()+Array.flat(1)let arr1 = ["it's Sunny in", "", "California"] arr1.map(x => x.split(" ")) // [["it's","Sunny","in"],[""],["California"]] arr1.flatMap(x => x.split(" ")) // ["it's","Sunny","in", "", "California"]
catch 参数可省略
支持语法 try {...} catch {...} .
Symbol.description
获取 Symbol 对象创建时的描述信息:
const symbol = Symbol("This is a symbol")
symbol // Symbol(This is a symbol)
symbol.description // "This is a symbol"
加强 JSON.parse() 与 JSON.stringify()
之前 JSON 字符串中包含行分隔符 \u2028 或 段落分隔符 \u2029 时, 调用 JSON.parse() 解析会报错, 修复了这个错误.
之前对于无效的 UTF-16 字符编码, JSON.stringify() 会被替换为无意义的特殊字符, 现在修复了这个错误:
JSON.stringify("\uD83D")
// 之前: '"�"'
// 目前: '"\\ud83d"'
Array.sort()更加稳定
之前的规范允许不稳定的排序算法如快排, 目前主流浏览器都使用稳定的排序算法, 对于传入的比较算法计算结果等于 0 的情况也能保持顺序稳定.
Function.toString() 重新修订
之前的 Function.toString() 只返回函数主体, 丢失了原始的注释和空格等信息.
现在 Function.toString() 返回的结果与函数编写的一致.
ES 2018
for await...of
用于遍历异步可迭代对象(也可遍历同步可迭代对象).
需要放在 async function 内部.
// 一个异步可迭代对象
const asyncIterable = {
[Symbol.asyncIterator]() {
return {
i: 0,
next() {
if (this.i < 3) {
return Promise.resolve({ value: this.i++, done: false })
}
return Promise.resolve({ done: true })
},
}
},
}
// 遍历异步可迭代对象
;(async function () {
for await (n of asyncIterable) {
console.log(n)
}
})()
Promise.finally()
当 Promise 执行结束时, 无论结果是 fulfilled 还是 rejected, 都会执行 finally 回调.
new Promise(...)
.then(...)
.catch(...)
.finally(...);
Object Rest Properties
对象剩余属性:
let obj = { a: "aa", b: 30, c: true, d: "" }
let { a, b, ...others } = obj
a // "aa"
b // 30
others // { c: true, d: "" }
New RegExp Features
新增 4 个 RegExp 新特性:
- Unicode 属性转义
\p{...} - 后行断言(lookbehind assertion)
(?<=...)(?<!) - 可命名捕获组
(?<name>...) - s (dotAll) Flag, 使用
s标志激活.字符匹配任意一个字符(dotAll 模式)
ES 2017
String Padding
使用另一个字符串(重复)填充当前字符串, 以达到指定长度
padStart左侧填充padEnd右侧填充
"abc".padStart(10) // " abc", 默认填充空格
"abc".padEnd(10) // "abc ", 右侧填充
"abc".padStart(10, "foo") // "foofoofabc", 用指定字符重复填充
"abc".padStart(5, "12345") // "12abc", 多余字符丢弃
"abc".padStart(2) // "abc", 若长度小于当前字符串则不变
Object.entries()
返回对象自身(不包括原型链)可枚举属性的键值对数组:
let o = { a: "aaa", b: 20 }
console.log(Object.entries(o)) // [['a', 'aaa'], ['b', 20]]
for (let [key, value] of Object.entries(o)) {
console.log(`${key}: ${value}`)
}
与 for..in 循环的顺序一致, 但 for..in 循环会枚举原型链中的属性.
Object.values()
返回对象自身的所有可枚举属性值的数组:
let o = { a: "aaa", b: 20 }
console.log(Object.values(o)) // ["aaa", 20]
Async Functions
使用 async await 关键字更简洁地书写基于 Promise 的异步行为.
Object.getOwnPropertyDescriptor()
获取对象的一个自有属性的属性描述符:
const obj = { a: "aaa" }
Object.getOwnPropertyDescriptor(obj, "a")
// {value: 'aaa', writable: true, enumerable: true, configurable: true}
函数参数列表中的尾随逗号
允许在函数声明和函数调用的参数列表中使用尾随逗号:
const func = (v1, v2,) => {...};
func("t1", "t2",);
同时也支持对象字面量和数组字面量后的逗号.
SharedArrayBuffer 和 Atomics
WebWorkers 可以创建多线程程序, 使用 SharedArrayBuffer 创建共享数组缓冲区, 使得多个 workers 和主线程之间可以共享数据.
全局对象 Atomics 提供了一组静态方法对 SharedArrayBuffer 和 ArrayBuffer 进行原子操作, 使得多个线程可以按规定顺序安全地读写同一位置的数据.
为了防止 Spectre 漏洞, 所有主流浏览器默认禁用 SharedArrayBuffer .
ES 2016
求幂运算符 **
let x = 2 ** 5;
等价于 Math.pow(x, y)
“幂等”运算符 **= , 如:
let x = 5;
x **= 2; // 相当于x = x ** 2
Array.includes()
let arr = ["1", "2", "3"];
arr.includes("1"); // true
arr.includes("4"); // false
ES6 (ES2015)
关键字和类型
let与const声明- 箭头函数
-
for/of遍历可迭代的数据结构: Array, String, Map, NodeList 等- 区分
for/in: 遍历所有可枚举属性, 适用于遍历 Object 属性
- 区分
Map对象Set对象class"面向对象"相关方法实现PromiseSymbol基本类型
Function
- Function 参数默认值
function fn(x = 2){...} - Function 剩余参数
function fn(a, b, ...others) {...}
String
String.includes()String.startsWith()String.endsWith()
Array
Array.from()从具有长度或可迭代的对象创建数组, 如 Set, String 等Array.keys()返回数组的索引迭代器Array.find()Array.findIndex()返回满足测试函数的第一个元素 / 元素索引.
Math
Math.trunc()截取整数部分Math.sign()返回数字的符号, 取值: 1, -1, 0, -0, NaN, 传入参数会被隐式转换为数字.Math.cbrt()立方根Math.log2()Math.log10()
Number
Number.EPSILON最小精度值, 两数之差小于此值可认为两数相等.Number.MIN_SAFE_INTEGERNumber.MAX_SAFE_INTEGER安全整数范围Number.isInteger()Number.isSafeInteger()
Global Methods
isFinite()参数为Infinity或NaN是返回false, 其他情况为trueisNaN()
Object
-
Object.entries()返回对象可枚举属性的键值对数组const o = { a: "aa", b: 2 }; console.log(Object.entries(o)); // [["a", "aa"], ["b", 2]]