ES6 中块级函数的精确语义是什么? [英] What are the precise semantics of block-level functions in ES6?

查看:12
本文介绍了ES6 中块级函数的精确语义是什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

  • ES6 中允许使用块级函数声明.
  • 他们升到街区的顶部.
  • 在严格模式下,它们在包含块之外不可见.

然而,由于这些语义的一部分被指定为可选"并且仅对 Web 浏览器是必需的(附件 B).所以我想填写下表:

<前>|在块外可见?|吊起?到什么程度?|TDZ"?|------------------------------------------------------------------------------------------------------------------------|非严格模式,没有网络扩展" |||||严格模式,没有网络扩展"|||||非严格模式,带有网络扩展 | | | ||严格模式,带有网络扩展" ||||

我也不清楚严格模式"在这种情况下的含义.这种区别似乎在 附录 B3.3,作为函数声明的运行时执行的一些附加步骤的一部分:

1.如果严格是假的,那么...

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

//非严格包围代码{函数 foo() {"使用严格";}}

在上表中应该被认为是严格模式"吗?然而,这与我最初的直觉相矛盾.

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

解决方案

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

没有.是的.它确实指的是函数的严格性(或脚本)在其中 包含函数声明的块出现.与要(或不)要声明的函数的严格性无关.

网络扩展"仅适用于草率(非严格)代码,并且仅当函数语句的外观是理智的"时——即,例如,如果它的名称与正式的参数或词法声明的变量.

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

所以我们基本上有

 |网络兼容纯-----------------+---------------------------------------------严格模式 ES6 |砌块吊装 砌块吊装草率模式 ES6 |它很复杂¹块吊装严格模式 ES5 |未定义的行为 ² SyntaxError草率模式 ES5 |未定义的行为 ³ SyntaxError

1:见下文.要求警告.
2:通常,会抛出SyntaxError
3:ES5.1 §12 中的注释谈到了实现"(例如这些).建议使用警告.

那么,对于具有遗留语义的 sloppy-mode 函数中的块中的函数声明,具有 Web 兼容性的 ES6 实现如何表现?
首先,纯语义仍然适用.也就是说,函数声明被提升到词法块的顶部.
但是,还有一个 var 声明,它被提升到封闭函数的顶部.
并且当函数声明被评估时(在块中,就好像它像一个语句一样被满足),函数对象被赋值给那个函数范围的变量.

这最好用代码来解释:

函数封闭(…){…{…功能兼容(…){…}…}…}

作用与

相同

函数封闭(…){var compat₀ = 未定义;//函数作用域…{let compat₁ = function compat(…) { … };//块作用域…兼容₀ = 兼容₁;…}…}

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

<块引用>

在块外可见?

是的,就像一个 var.但是,还有一个仅在块内可见的第二个绑定.

<块引用>

悬挂?

是 - 两次.

<块引用>

到什么程度?

函数(但用 undefined 初始化)和块(用函数对象初始化).

<块引用>

TDZ"?

不是在词法声明的变量(let/const/class)的时间死区的意义上,该变量在引用时抛出,不.但是在函数体执行中遇到函数声明之前,函数范围的变量是undefined(尤其是在块之前),如果你尝试调用它也会得到一个异常.

<小时>

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

I'm trying to wrap my head around the new standardized block-level functions in ES6 by reading the raw spec. My superficial understanding was:

  • Block-level functions declarations are allowed in ES6.
  • They hoist to the top of the block.
  • In strict mode, they aren't visible outside the containing block.

However, this is further complicated by the fact that part of these semantics are specified to be "optional" and only mandatory for web browsers (Annex B). So I would like have the following table filled:

                                             |  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" |                             |                               |          |

Also it is unclear to me what "strict mode" means in this context. This distinction seems to be introduced in Annex B3.3, as part of some additional steps for the runtime execution of a function declaration:

1. If strict is false, then
...

However, as far as I can see, strict refers to the [[Strict]] internal slot of the function object. Does this mean that:

// Non-strict surrounding code

{
    function foo() {"use strict";}
}

should be considered "strict mode" in the table above? However, that's contradicts my initial intuition.

Please, bear in mind that I'm mostly interested in the ES6 spec itself, regardless of actual implementation inconsistencies.

解决方案

As far as I can see, strict refers to the [[Strict]] internal slot of the function object.

No. And yes. It does refer to the strictness of the function (or script) in which the block that contains the function declaration occurs. Not to the strictness of the function that is (or is not) to be declared.

The "web extensions" do only apply to sloppy (non-strict) code, and only if the appearance of the function statement is "sane" - that is, for example, if its name doesn't collide with a formal parameter or lexically declared variable.

Notice that there is no difference between strict and sloppy code without the web-compatibility semantics. In pure ES6, there is only one behaviour for function declarations in blocks.

So we basically have

                 |      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: See below. Warnings are asked for.
2: Typically, a SyntaxError is thrown
3: The note in ES5.1 §12 talks of "significant and irreconcilable variations among the implementations" (such as these). Warnings are recommended.

So now how does an ES6 implementation with web compatibility behave for a function declaration in a block in a sloppy-mode function with legacy semantics?
First of all, the pure semantics still apply. That is, the function declaration is hoisted to the top of the lexical block.
However, there is also a var declaration that is hoisted to the top of the enclosing function.
And when the function declaration is evaluated (in the block, as if it was met like a statement), the function object is assigned to that function-scoped variable.

This is better explained by code:

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

works the same as

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

Yes, that's a bit confusing, having two different bindings (denoted with the subscripts 0 and 1) with the same name. So now I can succinctly answer your questions:

Visible outside of block?

Yes, like a var. However, there's a second binding that is visible only inside the block.

Hoisted?

Yes - twice.

Up to which point?

Both to the function (however initialised with undefined) and the block (initialised with the function object).

"TDZ"?

Not in the sense of the temporal dead zone of a lexically declared variable (let/const/class) that throws on referencing, no. But before the function declaration is encountered in the execution of the body, the function-scoped variable is undefined (especially before the block), and you'll get an exception as well if you try to call it.


Just for reference: in ES6, the above-described behaviour was specified only for blocks in function scopes. Since ES7 the same applies to blocks in eval and global scopes.

这篇关于ES6 中块级函数的精确语义是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆