跳到主要内容

顶层 `await`

· 阅读需 5 分钟
Myles Borins ([@MylesBorins](https://twitter.com/MylesBorins))

顶层 await 使开发者能够在异步函数之外使用 await 关键字。它像一个大的异步函数,使其他 import 它的模块在开始执行其主体之前会等待。

空值合并

· 阅读需 7 分钟
Justin Ridgewell

空值合并提案 (??) 添加了一个新的短路操作符,用于处理默认值。

你可能已经熟悉其他的短路操作符 &&||。这两个操作符处理“真值”和“假值”。假设代码示例为 lhs && rhs。如果 lhs(即左操作数)为假值,则表达式返回 lhs。否则,返回 rhs(即右操作数)。代码示例 lhs || rhs 的逻辑则相反。如果 lhs 为真值,则表达式返回 lhs。否则,返回 rhs

可选的链式操作

· 阅读需 5 分钟
Maya Armyanova ([@Zmayski](https://twitter.com/Zmayski)), 可选链的破除者

在 JavaScript 中长链式的属性访问可能容易出错,因为它们中的任何一个都可能会计算为 nullundefined(也称为“空值”)。在每一步检查属性的存在性容易演变为深度嵌套的 if 语句结构,或者带有长链属性访问的 if 条件语句。

将 JSON 嵌入 ECMAScript,也就是 JSON ⊂ ECMAScript

· 阅读需 6 分钟
Mathias Bynens ([@mathias](https://twitter.com/mathias))

通过 JSON ⊂ ECMAScript 提案,JSON 成为了 ECMAScript 的语法子集。如果你对此感到惊讶,你并不孤单!

ES2018 的旧行为

在 ES2018 中,ECMAScript 字符串字面量不能包含未转义的 U+2028 行分隔符和 U+2029 段分隔符字符,因为它们即使在该上下文中也被视为行终止符:

// 一个包含原始 U+2028 字符的字符串。
const LS = '
';
// → ES2018: 语法错误

// 一个包含原始 U+2029 字符的字符串,由 `eval` 生成:
const PS = eval('"\u2029"');
// → ES2018: 语法错误

这很麻烦,因为 JSON 字符串 可以 包含这些字符。因此,开发者不得不在将有效 JSON 嵌入到 ECMAScript 程序中时实现专门的后处理逻辑来处理这些字符。如果没有这样的逻辑,代码可能会出现细微的错误,甚至可能带来 安全问题

`Intl.NumberFormat`

· 阅读需 4 分钟
Mathias Bynens ([@mathias](https://twitter.com/mathias)) 和 Shane F. Carr

你可能已经熟悉了 Intl.NumberFormat API,因为它已经在现代环境中被支持了一段时间。

在其最基本的形式中,Intl.NumberFormat 允许创建一个可重用的格式化实例,该实例支持基于区域的数字格式化。就像其他 Intl.*Format API 一样,格式化实例支持 formatformatToParts 方法:

`globalThis`

· 阅读需 2 分钟
Mathias Bynens ([@mathias](https://twitter.com/mathias))

如果你之前为网页浏览器编写过 JavaScript,你可能用过 window 来访问全局 this。在 Node.js 中,你可能使用过 global。如果你编写的代码需要同时在这两种环境下运行,你可能会检测这些对象哪个可用,然后使用它——但是随着你想支持的环境和用例数量的增加,需要检查的标识符列表会迅速膨胀,事情变得复杂起来:

弱引用和终结器

· 阅读需 10 分钟
Sathya Gunasekaran ([@_gsathya](https://twitter.com/_gsathya)), Mathias Bynens ([@mathias](https://twitter.com/mathias)), Shu-yu Guo ([@_shu](https://twitter.com/_shu)), and Leszek Swirski ([@leszekswirski](https://twitter.com/leszekswirski))

一般来说,JavaScript 中对象的引用是_强引用_,这意味着只要你有对对象的引用,它就不会被垃圾回收。

const ref = { x: 42, y: 51 };
// 只要你可以访问到 `ref`(或其他对同一对象的引用),这个对象就不会被垃圾回收。

目前,WeakMapWeakSet 是在 JavaScript 中以某种方式弱引用对象的唯一方式:将一个对象作为键添加到 WeakMapWeakSet 中不会阻止它被垃圾回收。

const wm = new WeakMap();
{
const ref = {};
const metaData = 'foo';
wm.set(ref, metaData);
wm.get(ref);
// → metaData
}
// 我们在这个代码块作用域中不再拥有对 `ref` 的引用,因此它现在可以被垃圾回收,尽管它是 `wm` 中的一个键,而我们仍然可以访问到 `wm`。

稳定的 `Array.prototype.sort`

· 阅读需 3 分钟
Mathias Bynens ([@mathias](https://twitter.com/mathias))

假设你有一个由狗组成的数组,每只狗都有一个名字和一个评分。(如果这个例子听起来很奇怪,你应该知道有一个专门研究这个内容的 Twitter 帐号……别问!)

// 注意数组已经按 `name` 字母顺序预排序。
const doggos = [
{ name: 'Abby', rating: 12 },
{ name: 'Bandit', rating: 13 },
{ name: 'Choco', rating: 14 },
{ name: 'Daisy', rating: 12 },
{ name: 'Elmo', rating: 12 },
{ name: 'Falco', rating: 13 },
{ name: 'Ghost', rating: 14 },
];
// 按 `rating` 降序排序狗。
// (这个操作会原地更新 `doggos`。)
doggos.sort((a, b) => b.rating - a.rating);

Symbol.prototype.description

· 阅读需 1 分钟
Mathias Bynens([@mathias](https://twitter.com/mathias))

JavaScript 的 Symbol 可以在创建时赋予一个描述:

const symbol = Symbol('foo');
// ^^^^^

以前,唯一可以通过编程方式访问这个描述的方法是通过 Symbol.prototype.toString() 间接实现:

const symbol = Symbol('foo');
// ^^^^^
symbol.toString();
// → 'Symbol(foo)'
// ^^^
symbol.toString().slice(7, -1); // 🤔
// → 'foo'

然而,这段代码看起来有些魔幻,不是非常自解释,并且违反了“表达意图,而非实现”的原则。此外,上面的技巧也无法区分没有描述的 symbol(即 Symbol())和描述为空字符串的 symbol(即 Symbol(''))。

Object.fromEntries

· 阅读需 4 分钟
Mathias Bynens ([@mathias](https://twitter.com/mathias)), JavaScript 爱好者

Object.fromEntries 是内置 JavaScript 库的一个很有用的补充。在解释它的作用之前,先了解一下已有的 Object.entries API 会有所帮助。

Object.entries

Object.entries API 已经存在了一段时间。

对于对象中的每个键值对,Object.entries 会返回一个数组,第一个元素是键,第二个元素是值。

Object.entries 在与 for-of 结合使用时尤为有用,因为它可以非常优雅地迭代对象中的所有键值对:

const object = { x: 42, y: 50 };
const entries = Object.entries(object);
// → [['x', 42], ['y', 50]]

for (const [key, value] of entries) {
console.log(`The value of ${key} is ${value}.`);
}
// 输出:
// The value of x is 42.
// The value of y is 50.

遗憾的是,想从 entries 的结果回到等价对象并不容易……直到现在!

Object.fromEntries

新的 Object.fromEntries API 执行了 Object.entries 的逆操作。这使得根据条目重新构建对象变得更加简单:

const object = { x: 42, y: 50 };
const entries = Object.entries(object);
// → [['x', 42], ['y', 50]]

const result = Object.fromEntries(entries);
// → { x: 42, y: 50 }

一个常见的用例是转换对象。现在可以通过迭代其条目,然后使用你已经熟悉的数组方法来做到这一点:

const object = { x: 42, y: 50, abc: 9001 };
const result = Object.fromEntries(
Object.entries(object)
.filter(([ key, value ]) => key.length === 1)
.map(([ key, value ]) => [ key, value * 2 ])
);
// → { x: 84, y: 100 }

在这个示例中,我们用 filter 筛选出键长度为 1 的键值对,也就是 xy,而排除了 abc。然后用 map 对剩余的条目进行操作,并为每个条目返回一个更新后的键值对。在本例中,我们通过将值乘以 2 来使每个值翻倍。最终得到的是一个只包含属性 xy 的新对象,以及它们的新值。