ES6中块级作用域内函数声明会提升到该块顶部,块外不可调用但存在同名标识符,其行为类似let,导致块外访问报TypeError而非ReferenceError。

函数声明提升本身不报错,但会让代码执行顺序和开发者预期不一致,尤其在混用声明与表达式、同名变量/函数共存、或块级结构中定义函数时,容易出现“能运行但结果不对”或“某处报错却找不到原因”的情况。
同名函数与变量混用导致调用错乱
当函数名和变量名相同时,函数声明会完整提升到作用域顶部,而后续的变量赋值不会覆盖已提升的函数。这造成看似“被赋值”的变量,实际仍指向原函数。
-
典型表现:调用
foo()输出数字或字符串,但代码里写的是var foo = 42;—— 实际执行的是提升后的function foo() { return 12; } -
对比验证:若改用
var foo = function() { return 42; };,则foo()在声明前调用会报TypeError: not a function,因为只提升了foo变量名,值为undefined -
排查建议:遇到“本该是值却能调用”,立刻检查是否同名函数声明在后、变量赋值在前;用浏览器开发者工具的“断点+作用域面板”查看当前
foo的实际类型和值
函数表达式误当声明使用
函数表达式(const fn = function() {} 或 var fn = () => {})不提升函数体,只按变量规则处理——var 初始化为 undefined,let/const 进入暂时性死区(TDZ)。
-
典型报错:
`TypeError: bar is not a function`(
var bar = function() {};提升后bar是undefined) `ReferenceError: Cannot access 'baz' before initialization`(let baz = function() {};在声明前访问) - 关键区别:前者是运行时报错(值存在但不是函数),后者是语法级限制(根本不可访问)
-
排查建议:看到这类错误,先定位调用位置,再往上查最近的
var/let/const声明方式;避免在声明前调用,或统一用const+ 箭头函数,从源头规避提升歧义
块级结构中的函数声明行为不一致
非严格模式下,if、for 等块内声明的函数,在部分浏览器中会被提升至外层函数作用域,但规范未强制,导致跨环境表现不同。
-
典型现象:本地 Chrome 能直接调用
test(),上线后 Safari 报ReferenceError;构建工具(如旧版 Babel)可能默认转译成兼容写法,掩盖问题 - 根本原因:ES6 明确不鼓励块级函数声明,但历史代码仍大量存在;不同引擎对“块级函数是否可被外部访问”实现不一
-
排查建议:禁用块级函数声明,改用函数表达式并显式绑定作用域(如
const test = () => {}放在块内);开启严格模式("use strict"),让不合规声明提前报错
函数内部 var 变量遮蔽外部同名变量
函数体内用 var 声明与外层同名变量时,该声明会被提升至函数顶部,导致外层变量不可见,且初始值为 undefined。
-
典型表现:全局有
let name = 'Alice',函数内写console.log(name); var name = 'Bob';,输出却是undefined,而非Alice -
原理简析:
var name提升后,函数作用域内就只有一个name,它在赋值前始终是undefined,完全遮蔽了外部name -
排查建议:函数内避免用
var;优先用let或const,它们不会提升,也不会遮蔽外部同名变量;启用 ESLint 规则no-var和block-scoped-var自动拦截

















