ES6中块级函数的精确语义是什么?

我试图通过阅读原始规格来围绕ES6中新的标准化块级function。 我肤浅的理解是:

  • 在ES6中允许块级函数声明。
  • 他们耸立在街区的顶端。
  • 在严格模式下,它们在包含块外面不可见。

然而,由于这些语义的一部分被指定为“可选”并且仅对于web浏览器( 附录B )是强制性的,所以这变得更复杂。 所以我想填写下面的表格:

                                              | 可见的块外?  | 悬挂? 到哪个点?  |  “TDZ”?  |
 -------------------------------------------------- -------------------------------------------------- --------------------
 | 非严格模式,没有“networking扩展”|  |  |  |
 | 严格的模式,没有“networking扩展”|  |  |  |
 | 非严格模式,用“web extensions | | | |
 | 严格模式,使用“networking扩展”|  |  |  |

而且我不清楚在这方面“严格模式”是什么意思。 这个区别似乎在附录B3.3中介绍,作为函数声明的运行时执行的一些附加步骤的一部分:

1. If strict is false, then ... 

但是,就我所知, strict指的是函数对象的[[Strict]]内部槽。 这是否意味着:

 // Non-strict surrounding code { function foo() {"use strict";} } 

在上表中应该被认为是“严格模式”? 但是,这与我最初的直觉相矛盾。

请记住,我最感兴趣的是ES6规范本身,而不pipe实际的实现不一致。

就我所知, strict是指函数对象的[[Strict]]内部槽。

不是的 它引用了包含函数声明的块的函数( 或脚本 )的严格性。 不是(或不是)要声明的函数的严格性。

“networking扩展”只适用于不严格(非严格)的代码,并且只有当function语句的外观是“健全的” – 也就是说,例如,如果它的名字不与forms参数或词法冲突声明variables。

请注意,在没有Web兼容性语义的情况下,严格和粗糙的代码没有区别。 在纯粹的ES6中,块中的函数声明只有一个行为。

所以我们基本上有

  | web-compat pure -----------------+--------------------------------------------- strict mode ES6 | block hoisting block hoisting sloppy mode ES6 | it's complicated ¹ block hoisting strict mode ES5 | undefined behavior ² SyntaxError sloppy mode ES5 | undefined behavior ³ SyntaxError 

1:见下文。 警告被要求。
2:通常会引发SyntaxError
3: ES5.1§12中的注释谈到“实现中显着和不可调和的变化 ”(比如这些 )。 build议使用警告。

那么现在,具有Web兼容性的ES6实现如何在具有传统语义的马虎模式函数中的块中进行函数声明呢?
首先, 纯粹的语义仍然适用 。 也就是说,函数声明被提升到词法块的顶部。
但是,还有一个var声明被悬挂在封闭函数的顶部。
当函数声明被评估时(在块中,就好像它是像声明一样被满足的),函数对象被分配给该函数范围的variables。

代码更好地解释了这一点:

 function enclosing(…) { … { … function compat(…) { … } … } … } 

和…一样

 function enclosing(…) { var compat₀ = undefined; // function-scoped … { let compat₁ = function compat(…) { … }; // block-scoped … compat₀ = compat₁; … } … } 

是的,这有点令人困惑,有两个不同的绑定(用下标0和1表示)具有相同的名称。 所以现在我可以简洁地回答你的问题:

可见的块外?

是的,就像一个var 。 但是,还有一个只在块内部可见的绑定。

悬挂?

是的 – 两次。

到哪个点?

这两个函数(但undefined初始化)和块(用函数对象初始化)。

“TDZ”?

不是在引用引发的词法声明variables( let / const / class )的暂时死区的意义上,no。 但是在执行主体函数声明之前,函数范围variables是undefined (特别是在块之前),如果你试图调用它,你也会得到一个exception。

我不确定你的困惑来自哪里。 根据10.2.1 ,很清楚什么是“严格模式”。 在你的示例中, foo s [[Strict]]内部插槽将是true并且将处于严格模式,但托pipe它的块不会。 第一句(你引用的那句)与主机块有关,而不是它所产生的内容。 您的片段中的块不是严格模式,因此该部分适用于它。