深圳幻海软件技术有限公司 欢迎您!

第92次TC39会议举行,这些提案取得新进展!

2023-02-28

大家好,我是CUGGZ。TC39是一个推动JavaScript发展的技术委员会,由各个主流浏览器厂商的代表构成,其主要工作就是制定ECMAScript标准。TC39每两个月举行一次面对面会议。9月13日至16日,第92次TC39会议举行,该会议上以下提案取得新进展:Stage3:Array.from

大家好,我是 CUGGZ。

TC39 是一个推动 JavaScript 发展的技术委员会,由各个主流浏览器厂商的代表构成,其主要工作就是制定 ECMAScript 标准。TC39 每两个月举行一次面对面会议。9 月 13 日至 16 日,第 92 次 TC39 会议举行,该会议上以下提案取得新进展:

  • Stage 3:Array.fromAsync。
  • Stage 2:Well-Formed Unicode Strings,关于确定字符串是否是格式良好的 Unicode 的方法提议。
  • Stage 1:Extractors ,ECMAScript 的提取器。

对于提案,从提出到最后被纳入 ECMAScript 标准,总共分为五步:

  • stage0(strawman):任何TC39的成员都可以提交。
  • stage1(proposal):进入此阶段就意味着这一提案被认为是正式的了,需要对此提案的场景与API进行详尽的描述。
  • stage2(draft):演进到这一阶段的提案如果能最终进入到标准,那么在之后的阶段都不会有太大的变化,因为理论上只接受增量修改。
  • state3(candidate):这一阶段的提案只有在遇到了重大问题才会修改,规范文档需要被全面的完成。
  • state4(finished):这一阶段的提案将会被纳入到ES每年发布的规范之中。

1、Array.fromAsync

在 JavaScript 中内置了 Array.from 方法,它用于将类数组或者可迭代对象生成一个新的数组实例。在ECMAScript 2018中引入了异步可迭代对象。而JavaScript中一直缺少直接从异步可迭代对象生成数组的内置方法。proposal-array-from-async 提案中提出来的 Array.fromAsync 方法就是为了解决这个问题而提出来的。

下面来看一个简单的例子:

async function * asyncGen (n) {
  for (let i = 0; i < n; i++)
    yield i * 2;
}
// arr 将变为 [0, 2, 4, 6]`
const arr = [];
for await (const v of asyncGen(4)) {
  arr.push(v);
}

// 与上述方式是等价的
const arr = await Array.fromAsync(asyncGen(4));
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.

Array.fromAsync​ 可以将异步迭代转换为 promise​,并将解析为新数组。在 promise 解析之前,它将从输入值中创建一个异步迭代器,进行惰性的迭代,并将每个产生的值添加到新数组中。

与其他基于 Promise 的 API 一样,Array.fromAsync​ 总是会立即返回一个 promise​。当 Array.fromAsync​ 的输入在创建其异步或同步迭代器时引发错误时,则此 promise​ 状态将被置为 rejected。

提案地址:https://github.com/tc39/proposal-array-from-async​。

2、Well-Formed Unicode Strings

ECMAScript 中的字符串都是 UTF-16 编码的,ECMAScript 对整数值没有任何限制或要求,除非它们必须是 16 位无符号整数。在格式良好的字符串中,序列中的每个整数值代表一个 UTF-16 编码的 Unicode 文本的 16 位代码单元。但是,并非所有 UTF-16 代码单元序列都表示 UTF-16 编码的 Unicode 文本。在格式良好的字符串中,0xD800..0xDBFF 和 0xDC00..0xDFFF范围内的代码单元必须成对出现,并按顺序排列。具有不成对或无序代理项的字符串是格式不正确。

在 JavaScript 中,这可以通过正则表达式 test 来实现:

!/\p{Surrogate}/u.test(str);
  • 1.

或者使用以下算法:

function isWellFormed(str) {
  for (let i = 0; i < str.length; ++i) {
    const isSurrogate = (str.charCodeAt(i) & 0xF800) == 0xD800;
    if (!isSurrogate) {
      continue;
    }
    const isLeadingSurrogate = str.charCodeAt(i) < 0xDC00;
    if (!isLeadingSurrogate) {
      return false; // unpaired trailing surrogate
    }
    const isFollowedByTrailingSurrogate = i + 1 < str.length && (str.charCodeAt(i + 1) & 0xFC00) == 0xDC00;
    if (!isFollowedByTrailingSurrogate) {
      return false; // unpaired leading surrogate
    }
    ++i;
  }
  return true;
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.

目前没有内置的 API 可以实现这一点。因此,Well-Formed Unicode Strings 提案就是在 ECMA-262 中定义一种方法来验证给定的 ECMAScript 字符串是否格式正确。它提出了两个新方法[1]:

  • String.prototype.isWellFormed():用于判断字符串格式是否正确。
  • String.prototype.toWellFormed() :用于将字符串转换为正确格式。

提案地址:https://github.com/tc39/proposal-is-usv-string

3、Extractors

ECMAScript 目前没有在解构期间执行用户定义逻辑的机制,这意味着与数据验证和转换相关的操作可能需要多个语句:

function toInstant(value) {
  if (value instanceof Temporal.Instant) {
    return value;
  } else if (value instanceof Date) {
    return Temporal.Instant.fromEpochMilliseconds(+value);
  } else if (typeof value === "string") {
    return Temporal.Instant.from(value);
  } else {
    throw new TypeError();
  }
}

class Book {
  constructor({
    isbn,
    title,
    createdAt = Temporal.Now.instant(),
    modifiedAt = createdAt
  }) {
    this.isbn = isbn;
    this.title = title;
    this.createdAt = toInstant(createdAt);
    // 如果 `modifiedAt` 是 `undefined`,就会重复一些工作
    this.modifiedAt = toInstant(modifiedAt);
  }
}

new Book({ isbn: "...", title: "...", createdAt: Temporal.Instant.from("...") });
new Book({ isbn: "...", title: "...", createdAt: new Date() });
new Book({ isbn: "...", title: "...", createdAt: "..." });
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.

Extractors for ECMAScript 提案就是在 ECMAScript 中引入提取器(又名“提取器对象”)。提取器将增加 BindingPattern 和 AssignmentPattern 的语法以允许新的解构形式,如下例所示:

// binding patterns
const Foo(y) = x;           // instance-array destructuring
const Foo{y} = x;           // instance-object destructuring
const [Foo(y)] = x;         // nesting
const [Foo{y}] = x;         // ..
const { z: Foo(y) } = x;    // ..
const { z: Foo{y} } = x;    // ..
const Foo(Bar(y)) = x;      // ..
const X.Foo(y) = x;         // qualified names (i.e., a.b.c)
// assignment patterns
Foo(y) = x;                 // instance-array destructuring
Foo{y} = x;                 // instance-object destructuring
[Foo(y)] = x;               // nesting
[Foo{y}] = x;               // ..
({ z: Foo(y) } = x);        // ..
({ z: Foo{y} } = x);        // ..
Foo(Bar(y)) = x;            // ..
X.Foo(y) = x;               // qualified names (i.e., a.b.c)
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.

此外,这将利用 Pattern Matching 提案[2] 新添加的 Symbol.matcher​。使用新形式进行解构时,将调用 Symbol.matcher 方法,并将其结果进行解构。

使用 Extractors,可以在绑定模式中封装和重用验证和转换逻辑:

const InstantExtractor = {
  [Symbol.matcher]: value =>
    value instanceof Temporal.Instant ? { matched: true, value: [value] } :
    value instanceof Date ? { matched: true, value: [Temporal.Instant.fromEpochMilliseconds(value.getTime())] } :
    typeof value === "string" ? { matched: true, value: [Temporal.Instant.from(value)] } :
    { matched: false };
  }
};
class Book {
  constructor({
    isbn,
    title,
    createdAt: InstantExtractor(createdAt) = Temporal.Now.instant(),
    modifiedAt: InstantExtractor(modifiedAt) = createdAt
  }) {
    this.isbn = isbn;
    this.title = title;
    this.createdAt = createdAt;
    this.modifiedAt = modifiedAt;
  }
}
new Book({ isbn: "...", title: "...", createdAt: Temporal.Instant.from("...") });
new Book({ isbn: "...", title: "...", createdAt: new Date() });
new Book({ isbn: "...", title: "...", createdAt: "..." });
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.

提案地址:https://github.com/tc39/proposal-extractors。

​相关链接:

[1] isWellFormed()​和toWellFormed():https://tc39.es/proposal-is-usv-string/。

[2]  Pattern Matching 提案:https://github.com/tc39/proposal-pattern-matching​。