首页 > 解决方案 > `with` 语句中函数声明的范围

问题描述

前言:在 JavaScript 中不鼓励with使用 of是有充分理由的。它可能导致混淆代码和前向兼容性问题(例如,将新属性添加到内置对象时)。这个问题不是关于是否应该使用 - 它是关于.withwith

下面的代码应该工作吗?

let foo = {};
with(foo) {
  function bar() {
    console.log("hello");
  }
}
bar();

它适用于 Chrome 80,但不适用于 Firefox 72 TypeError: bar is not a function:.

编辑:原来这个错误只在粘贴到 Firefox 控制台(https://i.imgur.com/WTG3iiX.png)时发生,而不是在 HTML 文档中运行代码时发生。

但请注意它是 a TypeError,而不是ReferenceError(ie bar is not defined)。为了确认这一点,我们可以添加console.log("bar" in window)before bar();,并注意在 Firefox 中输出 true,而如果你在代码之前编写它,它会输出 false。所以在 Firefox 中,上面的代码具有设置window.barundefined.

这在 Firefox 和 Chrome 中都可以正常工作:

if(true) {
  function bar() {
    console.log("hello");
  }
}
bar();

正如我所预料的那样,因为function foo() {...}声明是函数范围的。因此,除非块作用域有什么奇怪的地方with,否则这似乎是一个 Firefox 错误?

标签: javascriptfirefoxscopewith-statement

解决方案


我无法重现 Firefox 73 的问题,因此 Firefox 的行为可能已经改变。

也就是说,请参阅MDN 关于 blocks 的主题

在严格模式下,从 ES2015 开始,块内的函数的作用域是该块。在 ES2015 之前,严格模式下禁止块级函数。

IIRC,提升规则和块之间的交互未定义,导致不同 JS 引擎中的行为不同。这与其说是 Firefox 的错误,不如说是语言本身定义中的错误。

避免在块中声明函数。


推荐阅读