欢迎您访问 最编程 本站为您分享编程语言代码,编程技术文章!
您现在的位置是: 首页

最完整的 JavaScript 新功能指南:ES2024 ~ ES2016

最编程 2024-05-03 21:56:56
...

ECMAScript与JavaScript

ECMAScript

  • 通常看做 JavaScript 的标准化规范
  • 实际上 JavaScriptECMAScript 的扩展语言, ECMAScript 只提供了最基本的语法,约定了代码该如何编写,只是停留在语言层面。

JavaScript

  • JavaScript 实现了 ECMAScript 的语言标准,并在其基础上做了一些扩展。
  • 在浏览器中环境中,JavaScript = ECMAScript + WebApis(BOM + DOM)

7abb3a79-36ce-4f31-b39b-7e95c215880d.webp

  • node 环境中,JavaScript = ECMAScript + NodeApis(fs,net等)

81853bef-6dbe-42c7-a807-4826e3cd579f.webp

  • 所以,JavScript语言本身指的就是ECMAScript

2015年开始,ES保持每年一个版本的迭代,ES6 其实等价于 ES2015,这个 ES2015 代表的是当时发表的年份,ES2016 发布的称为 ES7,依次类推,ES2023 可以称为 ES14 了,版本改动概览: 82fee2d6-0bd8-4bca-861c-67b7158628da.webp

ES2024

Well-Formed Unicode Strings

String原型上新增两个方法isWellFormedtoWellFormed isWellFormed() 方法返回一个表示该字符串是否包含单独代理项developer.mozilla.org/zh-CN/docs/… true,否则返回 false

const strings = [
  // 单独的前导代理
  "ab\uD800",
  "ab\uD800c",
  // 单独的后尾代理
  "\uDFFFab",
  "c\uDFFFab",
  // 格式正确
  "abc",
  "ab\uD83D\uDE04c",
];

for (const str of strings) {
  console.log(str.isWellFormed());
}
// 输出:
// false
// false
// false
// false
// true
// true

toWellFormed() 方法返回一个字符串,其中该字符串的所有单独代理项都被替换为 Unicode 替换字符 U+FFFD

const strings = [
  // 单独的前导代理
  "ab\uD800",
  "ab\uD800c",
  // 单独的后尾代理
  "\uDFFFab",
  "c\uDFFFab",
  // 格式正确
  "abc",
  "ab\uD83D\uDE04c",
];

for (const str of strings) {
  console.log(str.toWellFormed());
}
// Logs:
// "ab�"
// "ab�c"
// "�ab"
// "c�ab"
// "abc"
// "ab????c"

Atomics.waitAsync()

Atomics.waitAsync()静态方法在共享内存位置异步等待并返回一个Promise。与Atomics.wait()不同,waitAsync是非阻塞的,并且可以在主线程上使用。

const sab = new SharedArrayBuffer(1024);
const int32 = new Int32Array(sab);

const result = Atomics.waitAsync(int32, 0, 0, 1000);
// { async: true, value: Promise {<pending>} }

ArrayBuffer.prototype.resizable

resizable属性是一个访问器属性,其set访问器函数是未定义的,这意味着您只能读取该属性。该值是在构造数组时建立的。如果在构造函数中设置了maxByteLength选项,resizable将返回true;如果不是,它将返回false。当其为true时,则可以调整大小:

const buffer1 = new ArrayBuffer(8, { maxByteLength: 16 });
const buffer2 = new ArrayBuffer(8);

console.log(buffer1.resizable);
// Expected output: true

console.log(buffer2.resizable);
// Expected output: false

if (buffer1.resizable) {
  console.log("Buffer is resizable!");
  buffer.resize(12);
}

ES2023

从数组末尾查找元素

新增两个方法: .findLast().findLastIndex() 从数组的最后一个元素开始查找,可以同 find()findIndex() 做一个对比。

const arr = [{ value: 1 }, { value: 2 }, { value: 3 }, { value: 4 }];

// find vs findLast
console.log(arr.find(n => n.value % 2 === 1)); // { value: 1 }
console.log(arr.findLast(n => n.value % 2 === 1)); // { value: 3 }

// findIndex vs findLastIndex
console.log(arr.findIndex(n => n.value % 2 === 1)); // 0
console.log(arr.findLastIndex(n => n.value % 2 === 1)); // 2

Hashbang 语法

如下所示,在 index.js 脚本文件里编写 JS 代码,如果要正确的执行,需要在控制台输入 node index.js

console.log("JavaScript");

如果直接执行 ./index.js 脚本文件会得到以下报错:

./index.js
./index.js: line 1: syntax error near unexpected token `"JavaScript"'
./index.js: line 1: `console.log("JavaScript");' 

很正常,因为我们并没有指定使用何种解释器来执行上述脚本文件。Hashbang 语法是用来指定脚本文件的解释器是什么,语法规则是在脚本文件头部增加一行代码:#!/usr/bin/env node

// #!/usr/bin/env node
console.log("JavaScript");

注意,还需修改脚本文件的权限 chmod +x index.js,否则执行会报 permission denied: ./index.js 错误。

将 Symbols 作为 WeakMap 的键

这允许使用唯一的 Symbols 作为键。目前 WeakMaps 只允许对象作为键。因为它们共享同样的身份特性。

SymbolECMAScript中唯一的原始类型,允许使用唯一的值,因此可以使用Symbol作为键,而不是创建一个新的带有WeakMap的对象。

const weak = new WeakMap();const key = Symbol('my ref');
const someObject = { a:1 };weak.set(key, someObject);
console.log(weak.get(key));

通过复制改变数组

这在 Array.prototype 上提供了额外的方法,通过返回带有更改的新数组副本,而不是更新原始数组来更改数组。

新引入的 Array.prototype 函数包括:

  • Array.prototype.toReversed()
  • Array.prototype.toSorted(compareFn)
  • Array.prototype.toSpliced(start, deleteCount, …items)
  • Array.prototype.with(index, value)
const sequence = [1, 2, 3];
sequence.toReversed() // [3, 2, 1]
sequence // [1, 2, 3]

const outOfOrder = [3, 1, 2];
outOfOrder.toSorted() // [1, 2, 3]
outOfOrder // [3, 1, 2]

const array = [1, 2, 3, 4];
array.toSpliced(1, 2, 5, 6, 7) // [1, 5, 6, 7, 4]
array // [1, 2, 3, 4]

const correctionNeeded = [1, 1, 3];
correctionNeeded.with(1, 2) // [1, 2, 3]
correctionNeeded // [1, 1, 3]

ES2022

Class Fields

允许在类最外层声明类成员,参考 github.com/tc39/propos…

class Person {
  name = 'Tom'
}

私有化类成员:支持私有实例、私有静态类型字段、私有方法。

class Person {
  #privateField1 = 'private field 1'; // 私有字段赋初值
  #privateField2; // 默认 undefined
  static #privateStaticField3 = 'private static field 3'
  constructor(value) {
    this.#privateField2 = value; // 实例化时为私有字段赋值
  }
  #toString() {
    console.log(this.#privateField1, this.#privateField2, InstPrivateClass.#privateStaticField3);
  }
  print() {
    this.#toString()
  }
}
const p = new Person('private field 2')
p.print()

私有字段检查

使用 in 操作符检测某一实例是否包含要检测的私有字段。

class Person {
  #name = 'Ergonomic brand checks for Private Fields';
  static check(obj) {
    return #name in obj;
  }
}

Top-level await

以前 await 必须随着 async 一起出现,只有在 async 函数内才可用。当需要在一些文件顶部进行初始化的场景中使用时就有不支持了,* await 可以解决这个问题,但它仅支持 ES Modules

let jQuery;
try {
  jQuery = await import('https://cdn-a.com/jQuery');
} catch {
  jQuery = await import('https://cdn-b.com/jQuery');
}

正则新增 /d 修饰符

以前的正则表达式支持 3 个修饰符:/i(忽略大小写)、/g(全局匹配)、/m(多行),当执行正则表达式的 exec() 方法时,新增一个 /d 修饰符,它会返回一个 indices 属性,包含了匹配元素的开始、结束位置索引。

const str = 'ECMAScript_JavaScript'
const regexp = /sc/igd // 忽略大小全局匹配并返回匹配元素的开始、结束位置索引
console.log(regexp.exec(str).indices[0]) // [ 4, 6 ]
console.log(regexp.exec(str).indices[0]) // [ 15, 17 ]

// 包含组信息
const text = 'zabbcdef';
const re = /ab+(cd(ef))/d;
const result = re.exec(text);

result.indices; // [ [1, 8], [4, 8], [6, 8] ]

// 具名组匹配
const text = 'zabbcdef';
const re = /ab+(?<Z>cd)/d;
const result = re.exec(text);

result.indices.groups; // { Z: [ 4, 6 ] }

.at() 操作符

根据指定索引获取数组元素,不同的是它支持传递负数,例如 -1 获取最后一个元素。

const arr = ['a', 'b', 'c']
console.log(arr.at(0));
console.log(arr.at(-1)); // 等价于 arr[arr.length - 1]

Object.hasOwn()

Object.hasOwn() 提供了一种更安全的方法来检查对象是否具有自己的属性,适用于检查所有的对象。Object.prototype.hasOwnProperty() 方法遇到 obj = null 这种情况会报错,参见以下示例:

const person = Object.create({ name: 'Tom' })
person.age = 18;
console.log(Object.hasOwn(person, 'name')); // false
console.log(Object.hasOwn(person, 'age')); // true

// 遇到这种情况 hasOwnProperty 会报错
const p1 = null
console.log(p1.hasOwnProperty('name')); // TypeError: Cannot read properties of null (reading 'hasOwnProperty')

Error Cause

Error Cause 是由阿里巴巴提出的一个提案,为 Error 构造函数增加了一个 options,可设置 cause 的值为任意一个有效的 JavaScript 值。

例如,自定义错误 message,将错误原因赋给 cause 属性,传递给下一个捕获的地方。

try {
  await fetch().catch(err => {
    throw new Error('Request failed', { cause: err })
  })
} catch (e) {
  console.log(e.message);
  console.log(e.cause);
}

Class Static Block

类的静态初始化块是在类中为静态成员提供了一个用于做初始化工作的代码块。

class C {
  static x = 'x';
  static y;
  static z;
  static {
    try {
      const obj = doSomethingWith(this.x);
      this.y = obj.y;
      this.z = obj.z;
    } catch (err) {
      this.y = 'y is error';
      this.z = 'z is error';
    }
  }
}

ES2021

String.prototype.replaceAll

replaceAll() 用于替换正则表达式或字符串的所有匹配项,之前的 replace() 只会匹配一个。

console.log('JavaScript'.replaceAll('a', 'b')); // JbvbScript

Promise.any

Promise.any() 接收一个 Promise 数组做为参数,返回第一个执行成功的 Promise,如果全部执行失败将返回一个新的异常类型 AggregateError,错误信息会以对象数组的形式放入其中。

const delay = (value, ms) => new Promise((resolve, reject) => setTimeout(() => resolve(value), ms));
const promises = [
  delay('a', 3000),
  delay('b', 2000),
  delay('c', 4000),
];

Promise.any(promises)
  .then(res => console.log(res)) // b
  .catch(err => console.error(err.name, err.message, err.errors)) // 全部失败时返回:AggregateError All promises were rejected [ 'a', 'b', 'c' ]

数字分隔符

数字分隔符可以让大数字看起来也容易理解。

const budget = 1_000_000_000_000;
console.log(budget === 10 ** 12); // true

逻辑赋值运算符

结合了逻辑运算符 &&||?? 和逻辑表达式 =

a ||= b;
// 等效于以下两种写法
// a || (a = b); a为falsy时执行右边
// if(!a) a = b;

a &&= b;
// 等效于以下两种写法
// a && (a = b); a为truth时执行右边
// if(a) a = b

a ??= b;
// 等效于以下两种写法
// a ?? (a = b); a为undefined或null时执行右边
// if(a === nudefined || a === null) a = b;

WeakRef

WeakRef 对象包含对对象的弱引用,这个弱引用被称为该 WeakRef 对象的 target 或者是 referent。对对象的弱引用是指当该对象应该被 GC 回收时不会阻止 GC 的回收行为。而与此相反的,一个普通的引用(默认是强引用)会将与之对应的对象保存在内存中。只有当该对象没有任何的强引用时,JavaScript 引擎 GC 才会销毁该对象并且回收该对象所占的内存空间。

WeakRef()用来创建一个 WeakRef 对象。

WeakRef.prototype.deref()返回当前实例的 WeakRef 对象所绑定的 target 对象,如果该 target 对象已被 GC 回收则返回 undefined

const obj = { a: 1 };
const ref = new WeakRef(obj)
console.log(ref.deref()); // {a: 1}

ES2020

matchAll - 匹配所有

String.prototype.matchAll() 会返回正则匹配的所有字符串及其位置,相比于 String.prototype.match() 返回的信息更详细。

const str = 'JavaScript'
const regexp = /a/g
console.log([...str.matchAll(regexp)]);

// Output:
[
  [ 'a', index: 1, input: 'JavaScript', groups: undefined ],
  [ 'a', index: 3, input: 'JavaScript', groups: undefined ]
]

模块新特性

  • import 动态导入

动态导入意思是当你需要该模块时才会进行加载,返回的是一个 Promise 对象。只有在 ES Modules 模块规范下才支持

// index-a.mjs
export default {
  hello () {
    console.log(`hello JavaScript`);
  }
}

// index-b.mjs
import('./index-a.mjs').then(module => {
  module.default.hello(); // hello JavaScript
})
  • import.meta

import.meta 只能在模块内部使用,如果在模块外部使用会报错。

这个属性返回一个对象,该对象的各种属性就是当前运行的脚本的元信息。具体包含哪些属性,标准没有规定,由各个运行环境自行决定。一般来说,import.meta 至少会有下面两个属性。

import.meta.url 返回当前模块的 URL 路径。举例来说,当前模块主文件的路径是 foo.com/main.js,imp… 就返回这个路径。

import.meta.scriptElement 是浏览器特有的元属性,返回加载模块的那个<script>元素,相当于 document.currentScript 属性。

BigInt

BigInt 是新增的一种描述数据的类型,用来表示任意大的整数。因为原先的 JavaScript Number 类型能够表示的最大整数位 Math.pow(2, 53) - 1,一旦超出就会出现精度丢失问题。详情可参考这篇大数危机的文章 github.com/qufei1993/b…

9007199254740995 // 会出现精度丢失
9007199254740995n // BigInt 表示方式一
BigInt('9007199254740995') // BigInt 表示方式二

Promise.allSettled

Promise.allSettled() 会等待所有的 Promise 对象都结束后在返回结果。

const delay = (value, ms, isReject) => new Promise((resolve, reject) => setTimeout(() => isReject ? reject(new Error(value)) : resolve(value), ms));
const promises = [
  delay('a', 3000),
  delay('b', 2000, true),
];
Promise.allSettled(promises)
  .then(res => console.log(res))

// Output:
[
  { status: 'fulfilled', value: 'a' },
  {
    status: 'rejected',
    reason: Error: b
        at Timeout._onTimeout (/index.js:1:108)
        at listOnTimeout (node:internal/timers:564:17)
        at process.processTimers (node:internal/timers:507:7)
  }
]

全局对象globalThis

JavaScript 可以运行在不同的环境,浏览器为 windowNode.jsglobal。为了能够统一全局环境变量,引入了 globalThis

window === globalThis // 浏览器环境
global === globalThis // Node.js 环境

for-in 机制

ECMA-262 规范没有规定 for (a in b) ... 的遍历顺序,部分原因是所有引擎都有自己特殊的实现,现在很难就 for-in 完整顺序规范达成一致,但规范了一些供参考的实现行为,在不同的引擎下 for in 循环出来的内容顺序是可能不一样的,现在标准化了。

可选链操作符

可选链是一个很好的语法,使用 ?. 表示,能避免一些常见类型错误。

const obj = null;
obj.a // TypeError: Cannot read properties of null (reading 'a')
obj?.a // 使用可选链之后就不会报错了,会输出 undefined

空值合并操作符

空值合并语法使用 ?? 表示,和 || 这个语法类似,不同的是 ?? 有明确的规定,只有当左侧的值为 nullundefined 时才会返回右侧的值,例如,左侧是 0 也会认为是合法的。

const a = 0
a || 1 // 1
a ?? 1 // 0

ES2019

可选的 catch 参数

try {
 throw new Error('this is not a valid')
} catch {
 console.error(`error...`);
}

Symbol.prototype.description

创建 Symbol 对象时可以传入一个描述做为参数。如下所示,使用 symbol.description 可方便的获取到这个描述。

const symbol = Symbol('Hello World')
symbol.description // Hello World

函数的 toString() 方法修订

toString() 方法返回当前函数源代码的字符串,以前会省略注释和空格。

const fn = (a, b) => {
 // return a + b value
 const c = a + b;
 return c;
}
console.log(fn.toString()); 

Object.fromEntries

Object.fromEntries() 方法会把键值对列表转换为对象。同 Object.entries() 相反。

const arr = [ [ 'name', 'foo' ], [ 'age', 18 ] ];
const obj = Object.fromEntries(arr);
console.log(obj); // { name: 'foo', age: 18 }
console.log(Object.entries(obj)); // [ [ 'name', 'foo' ], [ 'age', 18 ] ]

消除前后空格

ES2019 之前有一个 trim() 方法会默认消除前后空格。新增的 trimStart()trimEnd() 方法分别用来指定消除前面、后面空格。

'  JavaScript  '.trim() // 'JavaScript'
'  JavaScript  '.trimStart() // 'JavaScript  '
'  JavaScript  '.trimEnd() // '  JavaScript'

数组 flat()、flatMap()

flat(depth) 可以实现数组扁平化,传入的 depth 参数表示需要扁平化的数组层级。

[['a'], ['b', 'bb'], [['c']]].flat(2) // [ 'a', 'b', 'bb', 'c' ]

flatMap() 方法是 map()flat() 方法的结合,该方法只能展开一维数组。

[['a'], ['b', 'bb'], [['c']]].flatMap(x => x) // [ 'a', 'b', 'bb', [ 'c' ] ]

更友好的 JSON.stringify

对于一些超出范围的 Unicode 字符串,为其输出转义序列,使其成为有效 Unicode

// Before
console.log(JSON.stringify('\uD800')) // "�"

// ES2019
console.log(JSON.stringify('\uD800')) // "\ud800"

JSON 超集

之前如果 JSON 字符串中包含有行分隔符(\u2028) 和段落分隔符(\u2029),那么在解析过程中会报错,现在对它进行了支持。

// Before
JSON.parse('"\u2028"')
// SyntaxError
// ES2019
JSON.parse('"\u2028"')
// ''

ES2018

异步迭代器for await...of

异步迭代器(asynchronous iterators),await 可以和 for...of 循环一起使用,以串行的方式运行异步操作。

async function process(array) {
  for await (let i of array) {
    doSomething(i)
  }
}

异步迭代在 Node.js 中用的会多些,使用 for-await-of 遍历异步数据。例如使用 MongoDB 查询数据返回值默认为一个游标对象,避免了一次性把数据读入应用内存,详情参考 github.com/qufei1993/b…

Promise.finally

Promise.finally 能保证无论执行成功或失败都一定被执行,可以用来做一些清理工作。

const connection = { open: () => Promise.resolve() }
connection
  .open()
  .then()
  .catch()
  .finally(() => {
    console.log('clear connection');
  })

新的正则表达式功能

  • 正则命名组捕获

正则命名组捕获使用符号 ?<name> 表示,对匹配到的正则结果按名称访问。如果具名组没有匹配,那么对应的 groups 对象属性会是 undefined

const regexp = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/u;
const result = regexp.exec('2023-01-01');
console.log(result.groups); // { year: '2023', month: '01', day: '01' }
  • 正则 Lookbehind 断言:github.com/tc39/propos…

先行断言指的是,x 只有在 y 前面才匹配,必须写成/x(?=y)/。比如,只匹配百分号之前的数字,要写成/\d+(?=%)/先行否定断言指的是,x 只有不在 y 前面才匹配,必须写成/x(?!y)/。比如,只匹配不在百分号之前的数字,要写成/\d+(?!%)/

/\d+(?=%)/.exec('100% of US presidents have been male')  // ["100"]
/\d+(?!%)/.exec('that’s all 44 of them')                 // ["44"]

后行断言正好与先行断言相反,x 只有在 y 后面才匹配,必须写成/(?<=y)x/。比如,只匹配美元符号之后的数字,要写成/(?<=\$)\d+/后行否定断言则与先行否定断言相反,x 只有不在 y 后面才匹配,必须写成/(?<!y)x/。比如,只匹配不在美元符号后面的数字,要写成/(?<!\$)\d+/

/(?<=\$)\d+/.exec('Benjamin Franklin is on the $100 bill')  // ["100"]
/(?<!\$)\d+/.exec('it’s is worth about €90')                // ["90"]
  • 正则表达式dotAll模式:s 修饰符,使得.可以匹配任意单个字符。 (小数点.)默认匹配除换行符之外的任何单个字符。

例如/.n/ 将会匹配 "nay, an apple is on the tree" 中的 'an''on',但是不会匹配 'nay'

如果 s ("dotAll") 标志位被设为 true,它也会匹配换行符。

/foo.bar/.test('foo\nbar'); // → false
/foo.bar/s.test('foo\nbar'); // → true
  • 正则表达式 Unicode 转义:github.com/tc39/propos…

通常使用 \d 匹配任何数字,\s 匹配任何不为空格的字符。 Unicode 属性转义,用 \p{} 匹配所有 Unicode 字符,否定为 \P{}

/^\p{ASCII_Hex_Digit}+$/u.test('0123456789ABCDEF') // true
/^\p{ASCII_Hex_Digit}+$/u.test('h')                // false

上面代码中,ASCII_Hex_Digit 是一个布尔属性,用于检查字符串是否仅包含有效的十六进制数字。

还有许多其他布尔属性,包括 Uppercase, Lowercase, White_Space, Alphabetic, Emoji 等。

^\p{Lowercase}$/u.test('h') // true
/^\p{Uppercase}$/u.test('H') // true

/^\p{Emoji}+$/u.test('H')   // false
/^\p{Emoji}+$/u.test('????????') // true

除了这些二进制属性之外,还可以检查任何 Unicode 字符属性以匹配特定值。

/^\p{Script=Greek}+$/u.test('ελληνικ?') // true
/^\p{Script=Latin}+$/u.test('hey') // true

在这个例子中,检查字符串是用希腊语还是拉丁字母写的。

Rest/Spread 属性

为对象解构提供了和数组一样的 Rest 参数和展开操作符, ES2015 中的作用对象仅限于数组;

const myObject = {
  a: 1,
  b: 2,
  c: 3,
}
const { a, ...x } = myObject
// a = 1
// x = { b: 2, c: 3 }

function foo({ a, ...param }) {
  console.log(a) // 1
  console.log(param) // {b: 2, c: 3}
}

解除模版字符串限制 - Lifting template literal restriction

Lifting template literal restriction” 翻译过来为 “解除模版字符串限制”,这个要结合 ES6 中的 “带标签的模版字符串” 来理解。

以下代码执行时,解析器会去查找有效的转义序列,例如 Unicode 字符以 "\u" 开头,例如 \u00A9,以下 "\unicode" 是一个非法的 Unicode 字符,在之前就会得到一个 SyntaxError: malformed Unicode character escape sequence 错误。ES2018 中解除了这个限制,当遇到不合法的字符时也会正常执行,得到的是一个 undefined,通过 raw 属性还是可以取到原始字符串。

function tag(strs) {
  console.log(strs[0]); // undefined
  console.log(strs.raw[0]); // "\\unicode and \\u{55}"
}
tag`\unicode and \u{55}`

ES2017

Object.values/Object.entries

Object.values() 静态方法返回一个给定对象的自有可枚举字符串键属性值组成的数组。,同 Object.keys() 相反。

const obj = { name: 'Tom', age: 18 }
console.log(Object.values(obj)); // [ 'Tom', 18 ]
// 字符串具有索引作为可枚举的自有属性
console.log(Object.values("foo")); // ['f', 'o', 'o']

Object.entries() 静态方法返回一个数组,包含给定对象自有的可枚举字符串键属性的键值对。

const obj = { name: 'Tom', age: 18 }
for (const [key, value] of Object.entries(obj)) {
  console.log(key, value);
}
// Output
// name Tom
// age 18

字符串补全

两个字符串补全方法 .padStart().padEnd() 分别在字符串的头部、尾部进行按目标长度和指定字符进行填充。

console.log('a'.padStart(5, '1')); // 1111a
console.log('a'.padEnd(5, '2')); // a2222

async/await

异步函数 async/await 现在开发必备了,无需多讲。

  • async funciont developer.mozilla.org/zh-CN/docs/…
  • await 操作符 developer.mozilla.org/zh-CN/docs/…
async function fn() { ... }
try {
  await fn();
} catch (err) {} 

Object.getOwnPropertyDescriptors

Object.getOwnPropertyDescriptors() 静态方法返回给定对象的所有自有属性描述符。

const obj = {
  name: 'Tom',
  run: () => ``,
};
console.log(Object.getOwnPropertyDescriptors(obj));
// {
//   name: {
//     value: 'Tom',
//     writable: true,
//     enumerable: true,
//     configurable: true
//   },
//   run: {
//     value: [Function: run],
//     writable: true,
//     enumerable: true,
//     configurable: true
//   }
// }

参数列表支持尾逗号

支持在函数声明及调用时末尾增加逗号而不报 SyntaxError 错误。

function add(a, b,) {
 return a + b;
}
add(1, 2,)

Shared memory and atomics

Shared memory and atomics,“共享内存和原子” 又名 “共享数组缓冲区”,可以在主线程和多个工作线程间共享对象的字节,能更快的在多个工作线程间共享数据、除 postMessage() 多了一种数据传输方式。

多线程间的内存共享会带来一个后端常遇见的问题 “竞态条件”,提案提供了全局变量 Atomics 来解决这个问题。详情参考 2ality.com/2017/01/sha… esnext-book.lishuaishuai.com/es2017/shar…

ES2016

Array.prototype.includes

当判断一个数组中是否包含指定值时,使用 includes() 会很实用。

['a', 'b'].includes('a') // true

求幂运算符

** 是求幂运算符,左侧是基数、右侧是指数。等价于之前的 Math.pow() 函数。

2 ** 3 // 8
Math.pow(2, 3) // 8