You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

两个函数声明的差异解析:Version 2可行、Version 1不可行的原因及调用区别

函数声明 vs 函数表达式:为啥Version 2能正常运行,Version 1却报错?

Alright, let's break down this super common JavaScript gotcha clearly. First, here are the typical code examples that match your question (since you didn’t share the exact code, this is the most frequent scenario for this behavior):

示例代码

Version 1(执行报错)

foo();
var foo = function() {
  console.log("Hello from Version 1");
};

Version 2(正常运行)

foo();
function foo() {
  console.log("Hello from Version 2");
}

根本原因:变量/函数提升(Hoisting)

两个版本行为差异的核心,在于JavaScript引擎执行代码前的预编译机制——提升:引擎会把变量和函数声明"提前"到当前作用域的顶部,但提升的规则对函数声明和函数表达式完全不同。

Version 1的执行逻辑

Version 1使用的是函数表达式:本质是把一个匿名函数赋值给变量foo。预编译阶段,引擎只会提升变量的声明var foo,不会提升后面赋值的函数体。

所以当你在开头调用foo()时,foo确实已经被声明了,但它的初始值是undefined。试图把undefined当作函数调用,自然会抛出TypeError: foo is not a function的错误。

如果按照引擎实际的执行顺序重写代码,会是这样:

var foo; // 变量被提升,此时值为undefined
foo(); // 调用undefined,触发报错
foo = function() {
  console.log("Hello from Version 1");
};

Version 2的执行逻辑

Version 2使用的是函数声明:预编译阶段,引擎会把整个函数(包括函数名和函数体)完整提升到作用域顶部。

当执行foo()时,函数已经完全可用,所以能正常调用执行。

引擎实际的执行顺序等价于:

function foo() {
  console.log("Hello from Version 2");
} // 整个函数被提升到顶部
foo(); // 函数已准备好,正常执行

调用时的核心区别

  • Version 1(函数表达式):只有在变量赋值完成后,foo才指向有效的函数。如果在赋值前调用会直接报错;赋值后调用才正常。而且后续可以重新给foo赋值(比如foo = 42),让它变成非函数类型的值。
  • Version 2(函数声明):在整个作用域内,函数会被优先提升,所以无论在作用域的哪个位置调用(只要在同一个作用域内),都能正常执行。需要注意的是,如果后面出现同名的变量或函数声明,会覆盖之前提升的函数。

额外补充:如果用ES6的let/const替代var写函数表达式(比如let foo = function() {}),在声明前调用会抛出ReferenceError——因为let/const不存在变量提升,变量会处于"暂时性死区",直到声明语句执行后才能访问。

内容的提问来源于stack exchange,提问作者Gergő Horváth

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 07:54:13