Function Expression vs Declaration:在 JavaScript 中如何选择?

面向初学者的在线Python训练器

轻松学习Python,无需理论负担。在浏览器中直接解决带自动检查的实践任务,无需安装任何东西。

开始课程

为什么这个问题连经验丰富的开发者都感到困惑?

\n

如果你曾经写过 JavaScript,那么你一定遇到过这两种声明函数的方式。它们看起来相似,但行为却截然不同。在 Stack Overflow 上,这个问题获得了数千次浏览和数十页的讨论。为什么?因为不理解 var functionName = function() {} 和 function functionName() {} 之间的区别,会导致难以排查的错误。

\n

今天,我们将一劳永逸地弄清楚这个主题。你将了解什么是 函数声明(function declaration) 和 函数表达式(function expression),变量提升(hoisting) 是如何工作的,以及何时使用哪种方式。我们开始吧!

\n\n

语法背后隐藏着什么?

\n

我们从基础开始。第一种方式是 函数声明(Function Declaration):

\n
function greet() {\n    console.log('你好!');\n}
\n

第二种是 函数表达式(Function Expression):

\n
const greet = function() {\n    console.log('你好!');\n};
\n

请注意:在第一种情况下,函数有名称并且位于行首。在第二种情况下,我们将一个匿名函数赋值给变量 greet。但最有趣的部分在于 JavaScript 如何处理这些声明。

\n\n

主要区别:变量提升(Hoisting)

\n

变量提升(Hoisting) 是 JavaScript 的一种机制,它会在代码执行前将变量和函数的声明移动到其作用域的顶部。但它在函数声明和函数表达式中的工作方式不同。

\n\n

函数声明(Function Declaration)会被整体提升

\n

当你使用 function functionName() {} 时,JavaScript 会将整个函数声明“提升”到顶部。这意味着你可以在代码中声明函数之前调用它:

\n
sayHello(); // "你好!"\n\nfunction sayHello() {\n    console.log('你好!');\n}
\n

代码将无错误地执行。这很方便,但可能会让初学者感到困惑。

\n\n

函数表达式(Function Expression)不会被提升

\n

对于 var functionName = function() {} 来说,情况则不同。只有变量的声明会被提升,而它的值(函数)则不会。函数保留在原位:

\n
sayHello(); // TypeError: sayHello is not a function\n\nvar sayHello = function() {\n    console.log('你好!');\n};
\n

为什么会这样?因为 var 会提升变量 sayHello 的声明(其值为 undefined),而函数的赋值只会在表达式所在的行发生。因此,在这一行之前,sayHello 是 undefined,尝试将其作为函数调用会导致错误。

\n\n

顺便提一下,如果你将 var 替换为 let 或 const,错误将会不同——ReferenceError: Cannot access 'sayHello' before initialization。这是因为 let 和 const 在声明之前不会被初始化(即所谓的“暂时性死区”)。

\n\n

作用域:另一个容易出问题的地方

\n

函数声明 和 函数表达式 都遵循作用域规则。但有一个细微差别。

\n\n

函数声明(Function Declaration)在块级作用域内可见

\n

尽管 函数声明 会被提升,但其作用域受限于块级作用域(在严格模式下):

\n
'use strict';\nif (true) {\n    function greet() {\n        console.log('在块内部');\n    }\n    greet(); // "在块内部"\n}\ngreet(); // ReferenceError: greet is not defined(在严格模式下)
\n

在非严格模式下,这样的声明会“泄露”到外部,但不应依赖于此。

\n\n

函数表达式(Function Expression)存在于其变量中

\n

对于 函数表达式,一切都可以预测:函数仅在变量可访问的地方可用。如果移动

博客

书籍推荐