【问题标题】:Error sometimes thrown with JavaScript code blockJavaScript 代码块有时会引发错误
【发布时间】:2020-12-01 09:15:42
【问题描述】:

我正在使用代码块来模拟 C 语言中的静态函数变量。这是基本设置:

{
    let bob = 5;
    function b() {
        console.log(bob++);
    }
}

现在在 chrome 中编译得很好,没有任何抱怨。然而,在 Safari 中,我得到了一个

SyntaxError: Unexpected identifier 'bob'. Expected a ':' following the property name 'let'.

我不知道是什么导致了这种差异,因为 Chrome 和 Safari 都处理 ECMAScript 6。

【问题讨论】:

  • 如果您发布实际代码而不是摘要会有所帮助。
  • 因为你已经将它包含在一个对象中,所有这些现在都是属性,所以试试:{ bob: 5, b: () => { console.log(bob++) }
  • @DominikMatis - 不,独立块不会创建对象。如果上面的代码如上所示,它会创建一个内部包含代码的独立块。
  • @Pointy 这是失败的实际(简化)代码。自己试试吧。
  • 是的,Safari 的错误

标签: javascript google-chrome safari


【解决方案1】:

根据错误消息,Safari 将您的块解释为对象文字。语法是有效的,但 Safari 似乎对此感到窒息。

当我在自己的控制台中尝试此操作时,我能够通过在块之后立即放置一条语句来使其工作:

{ let bob = 5; function b(){ console.log(bob++); } } console.log('foo');

但是,这似乎在没有创建闭包的情况下将函数提升到块范围之外,导致 ReferenceError 声称它找不到变量 bob

我尝试将其显式包装在一个函数中,并使用 use strict 声明启动该函数,以防它未在 strict mode 中运行,因为这会改变行为:

function strict() {
  'use strict';
  {
    let bob = 5;
    function b() {
      console.log(bob++);
    }
    return b;
  } 
}
strict()();

它成功了!

TL:DR;块处理在松散模式下很奇怪。在块内定义函数时使用严格模式。

【讨论】:

  • 函数应该被提升到块范围之外,因为函数声明的范围是老式的。
  • 我的措辞很糟糕。我已经编辑了答案以澄清它应该创建一个闭包,但不是。
【解决方案2】:

问题是代码处于松散模式并且您在块中声明了一个函数。块中的函数声明仅在 ES2015 中标准化,而且,它们在严格模式下有意义,但在松散模式下它们......很奇怪。

strict mode 中,您的代码可以正常工作,可能与您期望的一样,也可能不正常。 bob 可被b 访问...并且bobb 在该块之外都无法访问,除非您采取措施将它们暴露在该块之外。

这是一个示例,您可以使用它在 Safari 和 iOS Safari 上进行测试(我只有后者可用)。这个版本报错:

<script>
window.onerror = e => {
    document.body.insertAdjacentText("beforeend", String(e));
};
</script>
<script>
{
    let bob = 5;
    function b() {
        document.body.insertAdjacentText("beforeend", bob++);
    }

    b();
}
</script>

错误是:

ReferenceError: Can't find variable: bob

此版本有效:

<script>
window.onerror = e => {
    document.body.insertAdjacentText("beforeend", String(e));
};
</script>
<script>
"use strict"; // <============================
{
    let bob = 5;
    function b() {
        document.body.insertAdjacentText("beforeend", bob++);
    }

    b();
}
</script>

我还在最新版本的 JavaScriptCore(Apple 的 JavaScript 引擎)v265499 中复制了该行为。我安装了¹并在本地运行它(将console.log/insertAdjacentText 更改为print,这在大多数原始引擎可执行文件中都可用)并在松散模式下而不是在严格模式下得到相同的错误。


如果您希望 b 在街区外可用,您最好执行以下操作:

"use strict";
const b = (() => {
    let bob = 5;
    return function b() {
        console.log(bob++);
    };
})();
b();

这是一个很多笨重,但是...或者,let

"use strict";
let b;
{
    let bob = 5;
    b = function b() {
        print(bob++);
    };
}
b();

¹ 使用非常方便的jsvu utility

【讨论】:

  • @Pointy - 确认!块中的函数声明!我真是个白痴。
  • 嗯,是的,但是 OP 报告的错误很奇怪,如果 function 位置是问题,在我看来。
  • @Pointy - 哦同意了。但是松散模式块中函数声明的语义很奇怪(就它们的定义而言;这可能与可以为松散模式标准化的有限数量的常见行为中的任何一个都不匹配)。当你向它扔附件 B 的东西时,更是如此。 :-D 我只是觉得自己像个白痴。我的书中并没有关于它们的完整部分!
  • @theEpsilon - 大声笑对不起 - developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…。基本上,严格模式是在 ES5 中添加到 JavaScript 的一种模式,可以控制一些非常非常有问题的行为,并且可以为选择加入新严格变体的代码指定稍微不同、更合理的行为。你可以通过在编译单元的顶部(松散地,“文件”)或函数的顶部添加 "use strict"; 来做到这一点。另请注意,JavaScript 模块和 class 构造默认情况下是严格的。编码愉快!
猜你喜欢
  • 2020-03-25
  • 1970-01-01
  • 1970-01-01
  • 2016-03-04
  • 1970-01-01
  • 1970-01-01
  • 2018-06-06
  • 1970-01-01
  • 2021-10-28
相关资源
最近更新 更多