函数声明提升是引擎在创建执行上下文时将函数名与完整函数体一同绑定到作用域的过程,发生在变量赋值前且优先级高于var声明;函数表达式不提升。

函数声明提升不是“代码提前运行”,而是 JavaScript 引擎在创建执行上下文阶段,把函数名和完整函数体一起绑定到当前作用域的过程。它发生在变量赋值之前,且优先级高于 var 声明。
函数声明会被完整提升,包括函数体
只要语法是 function foo() { ... } 这种形式,引擎就会在预编译阶段把整个函数定义(名称 + 逻辑)挂到作用域中。因此可以在声明前调用:
foo(); // 正常输出function foo() { console.log('hi'); }
这不同于 var:后者只提升变量名,初始值为 undefined;而函数声明提升后,变量直接指向可执行的函数对象。
同名声明时,后写的函数覆盖先写的
多个同名函数声明共存时,提升阶段就完成覆盖——不是运行时行为,也不依赖执行顺序:
console.log(fn()); // 输出 2function fn() { return 1; }function fn() { return 2; }
最终生效的是最后一个函数声明,前面的被完全忽略。这种覆盖在代码加载解析时就已确定。
函数声明优先于 var 声明,但会被后续赋值覆盖
当函数声明与同名 var 声明并存,函数先绑定,var 后提升(仅声明),但后续的赋值语句仍会改写该标识符:
fn(); // 输出 "func"var fn = 'not a function';function fn() { console.log('func'); }console.log(fn); // 字符串 'not a function'
注意:调用 fn() 能成功,是因为函数声明已绑定;但之后 var fn = ... 的赋值操作会把 fn 改为字符串。
函数表达式不享受声明提升特权
像 var bar = function() {} 或 const baz = () => {} 都属于表达式,只有左侧变量名可能被提升(var)或触发暂时性死区(let/const),右侧函数体不会提前可用:
bar(); // TypeError: bar is not a functionvar bar = function() { return 'ok'; };qux(); // ReferenceErrorconst qux = () => 'ok';
这类写法强调“先声明、再赋值、后使用”,更符合直觉,也避免了提升带来的隐蔽问题。











