用于标记模板文字的TemplateObject数组是否被它们的领域弱引用?

Mik*_*uel 4 javascript weakmap ecmascript-6 template-strings tagged-templates

while (c) {
  tag`str0 ${e} str1`
}
Run Code Online (Sandbox Code Playgroud)

JavaScript运行时创建一个冻结的数组,Object.freeze(['str0 ', ' str1'])但具有附加.raw属性.

是否可以将该对象用作a中的键,WeakMap以避免每次循环时都必须基于数组重做工作?

const memoTable = new WeakMap
function tag(templateStrings, ...values) {
  let cached = memoTable.get(templateStrings)
  if (!cached) {
    // Compute cached and put it in the table for next time.
  }
  // Do something with cached and values
}
Run Code Online (Sandbox Code Playgroud)

12.2.9.3运行时语义:GetTemplateObject(templateLiteral)描述了如何缓存此值:

  1. 领域成为当前的领域记录.
  2. templateRegistry成为领域.[[TemplateMap]].

所以从tag上面的循环中使用它应该是相同的,这将是一个很好的属性的密钥.

在我看来,[[TemplateMap]]必须弱引用模板对象数组,否则

for (let i = 0; i < 1e6; ++i) {
  eval('(() => {})`' + i + '`');
}
Run Code Online (Sandbox Code Playgroud)

会泄漏记忆.

我没有在规范中看到任何内容,但是对于广泛使用的JavaScript引擎来说,标记字符串模板的WeakMap条目最终会被收集,而不是可重新进入的范围?

我问,因为我已经基于这个假设实现了一些东西,但还没弄清楚如何测试它.

log*_*yth 6

是否可以将该对象用作WeakMap中的键,以避免每次循环时都必须基于数组重做工作?

是的,这正是你要做的事情,这是模板文字的一大特色.

在我看来,[[TemplateMap]]必须弱引用模板对象数组,否则

for (let i = 0; i < 1e6; ++i) {
  eval('(() => {})`' + i + '`');
}
Run Code Online (Sandbox Code Playgroud)

会泄漏记忆.

它确实泄漏,因为[[TemplateMap]]它并不弱.:(

这是对当前规范的讨论的开放点.目前的讨论是规范是否应该改为,而不是具有[[TemplateMap]]全局状态,而是将其改为每个源文本位置.例如,现在

var id = v => v;
id`tpl` === id`tpl` // true
Run Code Online (Sandbox Code Playgroud)

是否可以打破这样创建两个单独的模板?如果是这样,那么至少有可能eval允许您的示例收集模板.

你可以在这里看到一些讨论,https://github.com/tc39/ecma262/issues/840,其中至少暂时可以解决这个问题.

  • +1用于挖掘该问题! (2认同)