为什么称其为函数表达式而不是函数声明?

3

我正在开始学习React,现在回到一些更基础的JavaScript概念。

我已经学会了函数表达式和函数声明之间的区别,但是仍然困惑于为什么函数表达式不被称为函数声明。

如果这是一个变量声明

const foo = 5;

那么为什么这被称为函数表达式呢?
const bar = function() {
    // Some code
};

在第二个例子中,“const bar”不是在声明吗?为什么函数表达式和函数声明被称为它们的样子?为什么函数表达式没有被称为函数声明,反之亦然?

1
有一些网络资源可以提供帮助,包括 https://kangax.github.io/nfe/#expr-vs-decl。 - Cat
const bar 的初始化是一个函数表达式,因为像这样初始化已声明变量的任何内容都是某种形式的表达式。 - Pointy
const foo 是变量声明,5 是一个表达式,而不是声明。考虑 const foo = 1 + 1。很明显,1 + 1 是需要计算的表达式。 - slebetman
第一个代码块是 StatementListStatementListItemDeclarationLexicalDeclarationLetOrConst BindingListconst LexicalBindingconst BindingIdentifier Initializerconst Identifier = AssignmentExpression → [跳过20步] → const foo = PrimaryExpressionconst foo = Literalconst foo = NumericLiteral → [跳过4步] → const foo = 5。第二个代码块在 LiteralFunctionExpression → 等处分歧。请参见规范FunctionDeclaration 来自 Declaration → _HoistableDeclaration_。 - Sebastian Simon
2个回答

2
有趣的问题。措辞可以有模糊的界限,这部分导致了混淆。
首先,一些粗略的定义:
- 表达式:我认为最好用一个例子来解释。 `2 * 2` 是一个表达式,因为你可以继续对它执行其他操作,比如 `2 * 2 - 3`。另一方面,在 JavaScript 中 `if (...)` 不是一个表达式,它不能解析成一个值,因此你不能在其上执行进一步的操作。例如 `if (...) {...} / 2` 是无效的。这个“定义”有一些漏洞,但应该足够回答这个问题。 - 声明:声明只是声明你要使用某个变量名。因此,在你的例子中, `const foo = 5`,实际上是 `const foo` 部分起到了声明的作用,`= 5` 只是初始化声明。
有了这个理解,让我们考虑两个函数的示例,并看看这些术语在这些示例中的应用:
1. `const g = function() {}`
这里有一个声明,const g。我们还看到有一个函数被创建并分配给了g。我们正在处理function() {}的结果(将其分配给某个东西),这意味着JavaScript将把它解释为函数表达式。
第2点:function f() {} 我们没有将此函数用作表达式(在创建后没有进行任何其他操作),因此JavaScript实际上会将其与我们的第一个示例区别对待。它将在本地命名空间中声明f,并应用function hoisting。如果您只是在function f() {}之前添加一个+,那么您将导致JavaScript将其解释为表达式,这些功能将被禁用。您可以在开发工具中尝试一下-输入+function f(){}const g = function f(){},然后f将保持未定义状态。
JavaScript中的函数关键字在不同的上下文中有不同的处理方式,这是该语言选择的核心。你几乎可以将“function”关键字看作具有两个不同的含义,所选的含义取决于上下文。每当函数用于表达式上下文或者它没有名称时,它就采用“表达式”形式,我们称之为“函数表达式”。否则,它采用另一种包含一些额外特性的形式,例如将函数名称声明为本地变量。这可能是为什么我们采用了将这种替代形式称为函数声明的原因。然而,正如OP所指出的那样,即使使用“const f = function() {}”,声明仍然会发生,只是不是通过“function”关键字进行的。
注:像“+function f() {}”这样的例子,f在与g相同的范围内不会被定义,但它确实在f的主体内部被定义。换句话说,任何命名的函数表达式都在其自身的主体内“声明”其名称。

非常微小的问题:一些表达式仍然依赖于上下文;您不能任意组合表达式。例如:await x 是一个表达式,但 () => await x 不是有效的,因为 await 没有直接在 async 函数内使用。此外,整个 const foo = 5 是一个声明。const foo = 5 来自 const Identifier = _AssignmentExpression_,它派生自 const _BindingIdentifier Initializer_,派生自 _LetOrConst LexicalBinding_,来自 LexicalDeclarationconst foo 是语法错误。 - Sebastian Simon
1
谢谢@user4642212 - 我已经将您的反馈纳入了答案中 - 我希望人们能够找到我解释不太准确的地方。而且,你是对的,整个const foo = 5既是声明又是默认初始化。我尝试划分这个语句的哪一部分声明了"foo"作为一个常量,哪一部分是默认初始化它,可能是不公平的,因为它们都需要才能工作 - 但我仍然保留它,因为这使得答案更容易理解(我已经澄清了我的措辞,让它听起来不那么强硬)。 - Scotty Jamison

0
为什么这被称为函数表达式?
将变量赋值,实际上是一个表达式。在你的例子foo = 5中,那是一个表达式。你还声明了foo,但它仍然是一个表达式。
同样地,在另一个例子const bar = function() {}中,被称为“函数表达式”,以区分函数声明和函数表达式。
函数表达式。
const bar = function() {
    // Some code
};

VS 函数声明

function foo() {
    // Some code
};

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接