跳到主要内容

13 篇博文 含有标签「io19」

查看所有标签

`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);

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 的新对象,以及它们的新值。

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 中使用这些数据需要事先嵌入,并与其他库代码一起发送。这不幸会增加这些库的打包体积,从而对加载时间、解析/编译成本以及内存消耗产生负面影响。