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

Javascript ES6中块级函数的精确语义是什么?,javascript,ecmascript-6,language-lawyer,Javascript,Ecmascript 6,Language Lawyer,我试图通过阅读原始规范来了解ES6中新的标准化块级函数。我的肤浅理解是: ES6中允许块级函数声明 他们吊到了楼顶 在严格模式下,它们在包含块外不可见 然而,由于这些语义中的一部分被指定为“可选”且仅对web浏览器()是强制性的,因此这一点更加复杂。因此,我希望填写下表: | Visible outside of block? | Hoisted? Up to which point? | "TDZ"? | ------------------------------------

我试图通过阅读原始规范来了解ES6中新的标准化块级函数。我的肤浅理解是:

  • ES6中允许块级函数声明
  • 他们吊到了楼顶
  • 在严格模式下,它们在包含块外不可见
然而,由于这些语义中的一部分被指定为“可选”且仅对web浏览器()是强制性的,因此这一点更加复杂。因此,我希望填写下表:

| Visible outside of block? | Hoisted? Up to which point? | "TDZ"? | ------------------------------------------------------------------------------------------------------------------------ | Non-strict mode, no "web extensions" | | | | | Strict mode, no "web extensions" | | | | | Non strict mode, with "web extensions | | | | | Strict mode, with "web extensions" | | | | 但是,据我所知,
strict
指的是函数对象的
[[strict]]
内部插槽。这是否意味着:

// Non-strict surrounding code

{
    function foo() {"use strict";}
}
在上表中是否应被视为“严格模式”?然而,这与我最初的直觉相矛盾


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

我不知道您的困惑来自何方。根据这项研究,很清楚什么是或不是“严格模式”。在您的示例中,
foo
s
[[Strict]]
内部插槽实际上是
true
并且将处于严格模式,但承载它的块不会。第一句话(您引用的那句话)与托管块有关,而不是其中生成的内容。片段中的块不是严格模式,因此该部分适用于它。

我不确定您的混淆来自何处。根据这项研究,很清楚什么是或不是“严格模式”。在您的示例中,
foo
s
[[Strict]]
内部插槽实际上是
true
并且将处于严格模式,但承载它的块不会。第一句话(您引用的那句话)与托管块有关,而不是其中生成的内容。片段中的块不是严格模式,因此该部分应用于它

在我看来,
strict
指的是函数对象的
[[strict]]
内部插槽

不,是的。它确实涉及函数()的严格性,其中包含函数声明的块出现。不符合(或不)要声明的函数的严格性

“web扩展”只适用于草率的(非严格的)代码,并且只适用于函数语句的外观为“sane”的情况——例如,如果其名称与形式参数或词汇声明的变量不冲突

请注意,没有web兼容性语义的严格代码和草率代码之间没有区别。在纯ES6中,块中的函数声明只有一种行为

所以我们基本上有

| web compat pure
-----------------+---------------------------------------------
严格模式ES6 |块吊装块吊装
马虎模式ES6 |这是一个复杂的模块吊装
严格模式ES5 |未定义行为²语法错误
松散模式ES5 |未定义行为³合成错误
1:见下文。需要警告。
2:通常会抛出一个
SyntaxError
3:注释中提到“实现之间的重大且不可调和的变化”(例如)。建议发出警告

那么,对于具有传统语义的松散模式函数中的块中的函数声明,具有web兼容性的ES6实现如何表现呢?
首先,纯语义仍然适用。也就是说,函数声明被提升到词法块的顶部。
但是,还有一个
var
声明
,它被提升到封闭函数的顶部。
当对函数声明求值时(在块中,就像语句一样),函数对象被赋值给该函数范围的变量

代码可以更好地解释这一点:

function enclosing(…) {
    …
    {
         …
         function compat(…) { … }
         …
    }
    …
}
工作原理与

function enclosing(…) {
    var compat₀ = undefined; // function-scoped
    …
    {
         let compat₁ = function compat(…) { … }; // block-scoped
         …
         compat₀ = compat₁;
         …
    }
    …
}
是的,这有点混乱,有两个不同的绑定(用下标0和1表示)具有相同的名称。现在我可以简明扼要地回答你们的问题:

在街区外可见吗

是的,就像一个
var
。但是,第二个绑定仅在块内部可见

吊装

是的,两次

到哪一点

函数(但使用未定义的
初始化)和块(使用函数对象初始化)

“TDZ”

不是在词汇声明变量(
let
/
const
/
class
)引发引用的时间死区的意义上,不是。但是在执行主体时遇到函数声明之前,函数范围的变量是
未定义的
(尤其是在块之前),如果你试图调用它,你也会得到一个异常


仅供参考:在ES6中,上述行为仅针对函数作用域中的块指定。这同样适用于
eval
中的块和全局范围

在我看来,
strict
指的是函数对象的
[[strict]]
内部插槽

不,是的。它确实涉及函数()的严格性,其中包含函数声明的块出现。不符合(或不)要声明的函数的严格性

“web扩展”只适用于草率的(非严格的)代码,并且只适用于函数语句的外观为“sane”的情况——例如,如果其名称与形式参数或词汇声明的变量不冲突

请注意,没有web兼容性语义的严格代码和草率代码之间没有区别。在纯ES6中,块中的函数声明只有一种行为

所以我们基本上有


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