javascript - 在条件语句中混合函数和 const/let 会导致 Safari 中出现 ReferenceError

标签 javascript safari scope

我们有这样的东西

if(true) {
    const a = 1;
    function myFunc() {
        alert(a);
    }

    myFunc();
}

在 Safari 11 中,这会导致“ReferenceError:找不到变量:a”

相同的代码在 Chrome 和 Firefox 中运行不会出现错误。

在 Safari 中使用“严格模式”解决该问题。

我认为主要问题是 const a 和 function myFunc 的范围不同。事实上,最后一个函数是一个全局函数,因为条件语句不会像为 let 和 const 那样为其中的函数创建 block 作用域(我想是出于遗留原因)。

我想知道 Safari 在这种情况下是否正确,因为我们混合了不同范围的内容。

是否有一些官方资源可以解释此案例?我在 caniuse 和 mdn 网站上都没有发现任何提及此行为的信息

最佳答案

多年来,规范中都没有定义 block 内的函数声明,但不同的 JavaScript 引擎允许它们。

由于该语法未在规范中定义并且被 javascript 引擎所允许,因此不同的引擎会执行不同的操作。有些将其视为语法错误,另一些则将 block 作用域中的函数声明视为函数表达式。某些引擎将 block 作用域中的函数声明视为同一作用域中的多个提升声明。

从 ES2015 开始,函数声明是规范的一部分,有两种处理方式:

  • 标准网络语义
  • 旧版网络语义

标准语义

使用标准语义,函数声明将转换为函数表达式,使用 let 关键字进行声明,并提升到 block 的顶部。标准语义在严格模式下生效。

因此,在严格模式下,JavaScript 引擎将处理您的代码,就好像它是这样编写的:

if(true) {
    let myFunc = function() {
       alert(a);
    }

    const a = 1;
    myFunc();
}

旧版 Web 语义

在浏览器的非严格模式下,旧版 Web 语义适用。当 block 作用域中的函数声明不被视为语法错误时,有three scenarios所有主要 javascript 引擎都以相同的方式处理它们。这三种情况是:

  1. 函数在单个 block 内声明和引用
  2. 函数在单个 block 内声明并可能使用,但也由不包含在同一 block 内的内部函数定义引用。
  3. 函数在单个 block 中声明并可能使用,但也在其中引用 后续区 block 。

除了 block 作用域中定义的函数的 let 变量之外,在包含函数作用域或全局作用域中还有一个使用 var 定义的变量。此 var 赋值不会提升到 block 的顶部,而是在代码中到达函数声明时完成。

JavaScript 引擎将非严格模式下的代码视为:

var varMyFunc;

if(true) {
    let myFunc = function() {
       alert(a);
    }

    const a = 1;

    varMyFunc = myFunc;    // at the place of function declaration
   
    myFunc();
}

您不应编写依赖于旧版 Web 语义的代码。相反,请使用严格模式来确保您的代码依赖于处理 block 作用域中的函数声明的标准规则。话虽如此,如果您有依赖于旧版 Web 语义的非严格模式下的遗留代码,您可以期望它能够跨浏览器工作。

关于javascript - 在条件语句中混合函数和 const/let 会导致 Safari 中出现 ReferenceError,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63810931/

相关文章:

c - C中的typedef结构问题

javascript - 带有动态过滤器的 onBeforeRequest 事件

javascript - 如何在 jquery 中对未命名函数调用 .call()?

javascript - 添加/删除 IFrame 时出现 IFrame 内存泄漏

html - CSS 背景图像不会出现在 Safari 中

css - safari 5 中的图像消失

函数声明的javascript范围

javascript - 如何使用 JavaScript 更改转换属性的 translateX() 值?

javascript - 当用户在不同的选项卡中时,jQuery 更改页面的标题

java - 在 switch 语句中保存未知子类类型的变量