【问题标题】:Why is a block-scoped function work outside the scope? [duplicate]为什么块作用域的函数在作用域之外工作? [复制]
【发布时间】:2018-12-24 13:31:22
【问题描述】:

我正在阅读 Kyle Simpson:ES6 & Beyond,我在 second chapter。在标题为“块范围函数”的部分中给出了一个示例:

{
    foo();                  // works!

    function foo() {
        console.log("works!");
    }
}

foo();                      // ReferenceError

console.log 是我为了可测试性添加的。)

我希望这段代码在第一次调用时成功运行foo,即使该函数是在调用下方定义的,并且在第二次调用时由于 ReferenceError 而崩溃,正如本书所声称的那样。但是,如果我在 Chromium(版本 71.0.3578.98(官方构建)快照(64 位))中运行它,则 function 调用都会成功执行,并且 "works!" 会两次输出到控制台。如果我在 FireFox 中运行相同的脚本,那么第一个函数调用不会记录任何内容,而第二个函数调用在范围之外输出"works!"。因此,Chromium 和 FireFox 的行为彼此不同,也与书中的预期不同。我已经在 babeljs.io 中编译了它,结果是:

"use strict";

{
    // works!

    var _foo = function _foo() {
        console.log("works!");
    };

    _foo();
}

foo(); // ReferenceError

奇怪的是,foo is 定义为function 作用域,(使用关键字var 代替关键字letconst),所以它可以从作用域外到达,但在作用域外调用范围没有更改为_foo,因此我们会出错,但是如果我们将脚本更改为

{
    foo();                  // works!

    function foo() {
        console.log("works!");
    }
}

window["foo"]();                        // ReferenceError

转译器不会将foo 的名称更改为_foo。通过所有这些实验,我得出的结论是,如果我打算拥有一个块范围的函数,我需要明确定义它,例如:

{
    foo();                  // works!

    let foo = function() {
        console.log("works!");
    };
}

foo();                      // ReferenceError

但是由于时间死区问题,即使是第一次调用 foo 也会崩溃。所以,我的问题是:为什么块范围的 function 在范围之外工作?

【问题讨论】:

  • 您正在查看的章节解释了这种情况。在 ES6 之前,实现是多种多样的。在“严格”模式下,Firefox 和 Chrome 都表现出 ES6 行为,将函数的范围严格限制在声明块中。
  • @Pointy 您似乎是对的,我已经对其进行了测试,并且行为与本书相符。但是,这本书没有提到严格模式的必要性,因此造成了混乱。如果您将其转换为答案,我会接受。

标签: javascript ecmascript-6


【解决方案1】:

正如 Kyle 的书中提到的,块中函数声明的语义在过去因实现而异。 (这可以解释为什么在代码风格的评论中通常不鼓励在块内声明函数。)

浏览器通常希望尽可能多的旧代码能够工作,因此对于一个相当重要的更改,例如 not 将块嵌套的 function 声明提升到包含函数范围的旧代码肯定会中断。因此,由于缺乏更好的选择,"use strict"; 标志将 ES6 语义“打开”。旧代码(可能)在任何地方都没有"use strict";,所以它会继续以旧方式运行(当然这一直是有风险的)。

【讨论】:

  • 所以原因是向后兼容。谢谢,Pointy,很好的答案!
  • 请注意,您始终可以通过记录一个针对 Kyle 的书的 Github 问题来请求提及 "use strict"; 如何影响它:)
猜你喜欢
  • 1970-01-01
  • 2015-08-22
  • 2017-05-26
  • 2016-10-04
  • 1970-01-01
  • 1970-01-01
  • 2015-12-13
  • 2013-04-17
  • 1970-01-01
相关资源
最近更新 更多