为什么函数声明作为 If 语句的主体不会导致 JavaScript 中的错误?

Why doesn't function declaration as body of If statement result in an error in JavaScript?

提问人:Urooj 提问时间:9/19/2023 最后编辑:InSyncUrooj 更新时间:9/25/2023 访问量:128

问:

在 MDN 文档的“语句和声明”中提到:

术语“语句”和“声明”在 JavaScript 的正式语法中具有精确的含义,这会影响它们在代码中的放置位置。例如,在大多数控制流结构中,正文只接受语句,例如if...还。如果使用声明而不是语句,则会是 SyntaxError。例如,let 声明不是语句,因此不能将其裸露形式用作 if 语句的主体。

以下代码将给出错误:

if(true) 
  let x = 0;

现在函数声明也只是声明,对吧?那么为什么下面的代码没有给出同样的错误呢?

if(true)
function foo() {}
javascript if-statement 条件语句 语法错误 language-lawyer

评论

1赞 TheMaster 9/19/2023
它们是一种不同类型的声明。stackoverflow.com/a/20140626
0赞 Ivar 9/19/2023
因为它是在表达式的上下文中使用,所以它不是函数声明,而是(命名的)函数表达式。
2赞 Nick Parsons 9/19/2023
@Ivar我也在想,但命名函数表达式的名称不是只在函数本身的主体内可用,而不是在函数本身的主体之外,即:给出一个错误,说没有定义。如果被视为函数表达式,那么我认为之后尝试执行它会失败,但相反它会起作用。我的猜测是它与规范的 Web 兼容性部分有关。+function bar() {}; bar();barfunction foo() {}
3赞 TheMaster 9/19/2023
Label 语句说:有一种遗留的语法允许在非严格代码中标记函数声明。我相信这里也是一样的。在严格模式下,第二个代码也会失败。
3赞 Bergi 9/19/2023
强相关:根据 ecmascript 的规定,函数声明不能位于 if 语句中

答:

-4赞 Ji aSH 9/19/2023 #1

因为使用 function 关键字声明函数会将其置于全局范围内。

做一个简单的测试:

if (true) {
   function foo(x) { return x+2 }
}
console.log(foo(5))

将导致控制台中的“7”,证明该函数实际上是在 if 之外定义的。

相反,在 if 中显式定义的变量将限定为 if。

请注意,此代码将引发错误,因为 bar 不会在 if 之外定义。

if (true) {
    const bar = function (x) { return x+2 }
}
console.log(bar(5))

评论

3赞 InSync 9/19/2023
这不是问题所在。
1赞 Bergi 9/19/2023
"使用 function 关键字声明函数会将其置于全局范围内“——这是完全错误的
2赞 InSync 9/19/2023 #2

版本 5.1 有一个专门针对此问题的注释

已知几种广泛使用的 ECMAScript 实现支持将 FunctionDeclaration 用作语句。但是,在应用于此类 FunctionDeclaration 的语义中,实现之间存在显着且不可调和的差异。由于这些不可调和的差异,使用 FunctionDeclaration 作为语句会导致代码在实现之间无法可靠地移植。建议 ECMAScript 实现禁止 FunctionDeclaration 的这种用法,或者在遇到此类用法时发出警告。ECMAScript 的未来版本可能会定义用于在 Statement 上下文中声明函数的替代可移植方法。

下一版到当前版,第二个结构由附录 B 中指定的附加功能覆盖,当主机是 Web 浏览器时,这是必需的:

IfStatement[Yield, Await, Return]

   if ( 表达式[+In, ?屈服?等待] FunctionDeclaration[?屈服?等待,~默认])