跳到主要内容

Promise 组合器

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

自从 ES2015 引入 Promise 后,JavaScript 支持的 Promise 组合器只有两个:静态方法 Promise.allPromise.race

目前有两个新提案正在进行标准化过程:Promise.allSettledPromise.any。随着这些新增内容,JavaScript 中将总共有四种 Promise 组合器,每种都支持不同的使用场景。

`Array.prototype.flat` 和 `Array.prototype.flatMap`

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

Array.prototype.flat

这里的数组是多层嵌套的:它包含一个数组,而这个数组又包含另一个数组。

const array = [1, [2, [3]]];
// ^^^^^^^^^^^^^ 外层数组
// ^^^^^^^^ 内层数组
// ^^^ 最内层数组

Array#flat 返回给定数组的扁平化版本。

array.flat();
// → [1, 2, [3]]

// …等价于:
array.flat(1);
// → [1, 2, [3]]

数字分隔符

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

大型数字字面量对人眼来说难以快速解析,特别是当数字中有大量重复数字时:

1000000000000
1019436871.42

为了提高可读性,一个新的JavaScript语言特性允许在数字字面量中使用下划线作为分隔符。因此,上述内容现在可以改写为按千分进行分组,例如:

`String.prototype.matchAll`

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

通常会在字符串上重复应用相同的正则表达式以获取所有匹配项。在一定程度上,现在可以通过使用 String#match 方法来实现这一点。

在这个例子中,我们找到所有仅包含十六进制数字的单词,并记录每个匹配项:

const string = '魔术十六进制数字:DEADBEEF CAFE';
const regex = /\b\p{ASCII_Hex_Digit}+\b/gu;
for (const match of string.match(regex)) {
console.log(match);
}

// 输出:
//
// 'DEADBEEF'
// 'CAFE'

然而,这只会给你匹配的子字符串。通常,你不仅仅想要子字符串,还需要其他信息,比如每个子字符串的索引或者每个匹配中的捕获组。

通过编写你自己的循环,并自己记录匹配对象也可以实现这一点,但这有点麻烦而且不太方便:

const string = '魔术十六进制数字:DEADBEEF CAFE';
const regex = /\b\p{ASCII_Hex_Digit}+\b/gu;
let match;
while (match = regex.exec(string)) {
console.log(match);
}

// 输出:
//
// [ 'DEADBEEF', index: 19, input: '魔术十六进制数字:DEADBEEF CAFE' ]
// [ 'CAFE', index: 28, input: '魔术十六进制数字:DEADBEEF CAFE' ]

新的 String#matchAll API 使得这一过程比以往更加简单:你现在可以编写一个简单的 for-of 循环来获取所有的匹配对象。

const string = '魔术十六进制数字:DEADBEEF CAFE';
const regex = /\b\p{ASCII_Hex_Digit}+\b/gu;
for (const match of string.matchAll(regex)) {
console.log(match);
}

// 输出:
//
// [ 'DEADBEEF', index: 19, input: '魔术十六进制数字:DEADBEEF CAFE' ]
// [ 'CAFE', index: 28, input: '魔术十六进制数字:DEADBEEF CAFE' ]

String#matchAll 对于带有捕获组的正则表达式特别有用。它为每个匹配提供完整的信息,包括捕获组。

const string = '喜欢的 GitHub 仓库:tc39/ecma262 v8/v8.dev';
const regex = /\b(?<owner>[a-z0-9]+)\/(?<repo>[a-z0-9\.]+)\b/g;
for (const match of string.matchAll(regex)) {
console.log(`${match[0]}${match.index} 上,输入为 '${match.input}'`);
console.log(`→ 所有者: ${match.groups.owner}`);
console.log(`→ 仓库: ${match.groups.repo}`);
}

`Intl.ListFormat`

· 阅读需 3 分钟
Mathias Bynens ([@mathias](https://twitter.com/mathias)) 和 Frank Yung-Fong Tang

现代的网页应用通常使用包含动态数据的列表。例如,一个照片查看器应用可能会显示如下内容:

此照片包含了 Ada、Edith 和 Grace

而一个基于文本的游戏可能需要展示不同形式的列表:

选择你的超级能力: 隐身、心灵致动 或 共情

由于每种语言具有不同的列表格式化惯例和用词,实现一个本地化列表格式化工具是极其复杂的。这不仅需要列出每种语言中所有的单词(如上述例子中的 “和” 或 “或”),还需要在编码时定义这些语言的具体格式化规则。Unicode CLDR 提供了这些数据,但在 JavaScript 中使用这些数据需要事先嵌入,并与其他库代码一起发送。这不幸会增加这些库的打包体积,从而对加载时间、解析/编译成本以及内存消耗产生负面影响。

公共和私有类字段

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

多个提案扩展了现有的JavaScript类语法,新增了功能。本文解释了V8 v7.2和Chrome 72中的公共类字段的新语法,以及即将到来的私有类字段语法。

以下是一个创建名为IncreasingCounter的类实例的代码示例:

const counter = new IncreasingCounter();
counter.value;
// 输出 '获取当前值!'
// → 0
counter.increment();
counter.value;
// 输出 '获取当前值!'
// → 1

注意,访问value会执行一些代码(例如打印一条消息)然后返回结果。现在请思考,如何在JavaScript中实现这个类呢?🤔

ES2015类语法

以下是使用ES2015类语法实现IncreasingCounter的方法:

class IncreasingCounter {
constructor() {
this._count = 0;
}
get value() {
console.log('获取当前值!');
return this._count;
}
increment() {
this._count++;
}
}

该类在原型上安装了value的getter和一个increment方法。更有趣的是,类具有一个构造函数,该构造函数创建了一个实例属性_count并将其默认值设置为0。目前我们倾向于使用下划线前缀来表示_count不应该被类的使用者直接使用,但这只是一种约定,并不是一种真正的由语言强制执行的“私有”属性。

`Intl.RelativeTimeFormat`

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

现代 Web 应用程序通常使用诸如“昨天”、“42 秒前”或“3 个月后”的短语代替完整的日期和时间戳。这种 相对时间格式化值 已经变得如此普遍,以至于许多流行的库都实现了以本地化方式格式化它们的工具函数。(例如 Moment.jsGlobalize、和 date-fns。)

格式良好的 `JSON.stringify`

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

JSON.stringify 之前被规范为在输入包含任何独立代理对时返回格式不良的 Unicode 字符串:

JSON.stringify('\uD800');
// → '"�"'

“格式良好的 JSON.stringify”提案 修改了 JSON.stringify,使其对独立代理对输出转义序列,从而使其输出为合法的 Unicode(且可表示为 UTF-8):

JavaScript 模块

· 阅读需 21 分钟
Addy Osmani ([@addyosmani](https://twitter.com/addyosmani)) 和 Mathias Bynens ([@mathias](https://twitter.com/mathias))

JavaScript 模块现在已经在所有主流浏览器中支持

本文解释了如何使用 JS 模块、如何合理地部署它们,以及 Chrome 团队如何努力在未来使模块更加完善。

什么是 JS 模块?

JS 模块(也称为“ES 模块”或“ECMAScript 模块”)是一个重要的新功能,或者说是一组新功能集合。你可能以前使用过用户级的 JavaScript 模块系统。可能使用过类似 Node.js 的 CommonJS,或者AMD,或者其他什么。这些模块系统都有一个共同点:它们允许你导入和导出内容。