函数声明优先于函数表达式被提升:声明以function开头构成独立语句,整体会被提升;表达式是值的一部分,仅变量名提升,函数体需执行时创建。

识别函数声明与函数表达式在 V8 预编译阶段的优先级差异,关键看「语法位置」和「是否构成完整语句」——不是看有没有名字,也不是看写在哪一行,而是看它在代码中扮演的角色。
看语法结构:声明是独立语句,表达式是值的一部分
函数声明必须是一个完整的、可独立存在的语句,以 function 关键字开头,后跟函数名、括号、花括号,结尾有分号或换行(语句结束):
-
function foo() { }✅ 是声明 —— 编译阶段被完整提升(函数名 + 函数体) -
if (true) function bar() { }❌ 在非严格模式下可能被提升,但属于非标准用法;严格模式报错 -
var fn = function() { }✅ 是表达式 —— 只有fn变量名被提升(值为undefined),function() { }本身不提升 -
!function() { }()✅ 是表达式 —— 开头的!强制引擎将其解析为表达式,用于 IIFE
看提升结果:声明覆盖变量,表达式不抢位置
V8 在编译阶段按固定顺序处理标识符:先函数声明 → 再 var 声明 → 最后忽略重复声明。这意味着:
- 同名的
function a() { }和var a同时存在时,a 一开始指向函数 - 后续执行
var a = 123不是重新声明,只是赋值,a从此变成数字 - 但
var b = function() { }中的b在编译阶段只被声明为undefined,函数体要等到执行到这一行才创建 - 所以
b()放在var b = ...前面会报TypeError: b is not a function
看错误反馈:调用时机直接暴露类型
运行时行为是最直观的判断依据:
- 能在定义前调用 → 大概率是函数声明(如
foo(); function foo() {}) - 定义前调用报
ReferenceError或TypeError→ 很可能是函数表达式(如bar(); var bar = function() {}) - 报
TypeError: xxx is not a function且变量已声明 → 说明该变量存在但值还不是函数,基本可断定是表达式赋值未执行 - 多个同名
function name() {}连续出现 → 后者完全覆盖前者,最终生效的是最后一个,这是声明提升的叠加效果
看 V8 内部作用域快照(进阶验证)
用调试命令观察真实提升行为:
- 保存代码为
test.js,含function a() {}和var b = function() {} - 执行:
v8-debug --print-scopes test.js - 输出中会看到:
VAR a对应一个NormalFunction地址,而VAR b的值为undefined,无函数地址 - 这说明:a 是函数对象直接入驻作用域;b 只是空变量,函数对象尚未生成










