函数声明先于var变量声明被完整提升并绑定,var仅提升标识符不覆盖函数,赋值时才覆盖函数引用;同名时typeof在赋值前为"function",赋值后为新值类型。

函数声明提升优先于变量声明提升,但变量赋值会覆盖函数声明。
函数和变量同名时,提升顺序如何?
在同一个作用域中,如果出现同名的函数声明和变量声明(var),JavaScript 引擎在创建执行上下文阶段会:
- 先登记函数声明(函数名 + 函数体都可用)
- 再登记变量声明(var a 只提升标识符,不覆盖已登记的函数)
- 最后执行赋值语句(a = ...)——此时才真正覆盖函数
所以:typeof a 在赋值前是 "function",赋值后变成对应值的类型(如 "number" 或 "string")。
常见错误场景与结果
以下代码执行后输出什么?
console.log(a); // function a() {}
function a() { console.log(1); }
var a = 2;
console.log(a); // 2
原因:
- 第一行 console.log(a) 时,a 已被函数声明完全提升,所以输出函数体
- var a = 2 拆分为 var a(提升,但不覆盖函数)和 a = 2(执行时赋值,覆盖函数)
如何避免这类冲突?
根本解法不是靠记忆优先级,而是从编码习惯上切断隐患:
- 用 const 或 let 声明函数:例如 const fn = () => {},不会被提升,也不会与函数声明冲突
- 禁止在函数内用 var 声明与外层同名变量,尤其避免遮蔽函数名
- 启用 "use strict",配合 ESLint 规则(如 no-func-assign、no-shadow)提前报错
- 保持函数声明统一放在作用域顶部,不混写变量声明和函数声明
let/const 和 var 的关键区别
使用 let 或 const 声明同名标识符时:
- 不会发生“变量提升”,而是进入暂时性死区(TDZ)
- 若在声明前访问,直接抛出 ReferenceError,不给模糊行为留余地
- 即使有同名函数声明,let a = ... 也会报错,不允许覆盖
这比 var 下“看似能跑、实则逻辑错乱”的情况更安全、更可预测。

















