为什么非严格模式下该JS代码最后输出3 a: 1而非3 a: 5?
核心原因:非严格模式下块内函数声明的特殊提升规则
这个现象是ES规范为了兼容旧代码留下的历史遗留行为,仅在非严格模式下生效。严格模式中块内函数声明只会提升到块顶部,不会对外层作用域产生影响。
逐阶段执行逻辑拆解
先明确非严格模式下块级函数的两个特殊规则:
- 块内的
function a()声明会做两次提升:一次提升到外层作用域(本次是全局作用域),初始值为undefined;第二次提升到当前块的顶部,初始值为函数本身 - 当代码执行到
function a()原本所在的行位置时,会自动把当前块内a的最新值同步覆盖到外层作用域的a上
整个代码的执行流程如下:
全局预编译阶段
扫描到全局var a和块内function a()两个声明,非严格模式下块内函数仅给全局a绑定标识,初始值为undefined,因此第一行console.log('1 a: ' + a)输出undefined。进入if块执行
- 块预编译阶段,
function a()提升到块顶,块作用域内的a初始值为函数对象 - 执行
a = 1:修改的是块作用域内的a,此时块内a=1,全局a还是undefined - 执行到
function a() { }所在行:触发同步逻辑,把块内a的当前值1同步到全局a,此时全局a=1 - 执行
a = 5:修改的仍然是块作用域内的a,块内a=5,全局a保持1不变 - 执行块内打印,读取块内的
a,输出2 a: 5
- 块预编译阶段,
退出if块执行最后一行打印
块作用域销毁,此时访问的是全局作用域的a,值为之前同步的1,因此输出3 a: 1,而非块内最后赋值的5。
验证规则的小测试
你可以调整代码验证逻辑:
- 把
function a() { }移到a = 5之后,最后全局打印结果就会变成5,因为触发同步时块内a已经是5了 - 开头加
'use strict'开启严格模式,最后全局打印结果也会是5,因为严格模式下块内函数不会同步到外层作用域
内容的提问来源于stack exchange,提问作者MurphyChen
相关产品推荐
相关产品推荐

