函数声明的变量提升机制是怎样的?块级作用域内外为何表现不同?
理解块级函数声明的提升行为
首先咱们先把你的代码完整贴出来,方便一步步分析:
console.log("1:"+foo); { console.log("2:"+foo); function foo(){ console.log("checked"); } console.log("3:"+foo); } console.log("4:"+foo);
这个现象的核心是ES6标准对块级函数声明的提升规则做了明确调整,和传统全局/函数作用域里的函数提升逻辑有差异,咱们分阶段拆解:
1. 全局作用域的预编译阶段
在代码正式执行前,JavaScript引擎会先扫描全局作用域:
- 发现块级作用域内有
function foo()声明,会在全局作用域提前创建一个名为foo的变量(这是ES6非严格模式下的规则:块级函数会提升到外层作用域),但只做声明,不会赋值,所以此时全局的foo是undefined。 - 这就是第一个
console.log("1:"+foo)输出1:undefined的原因。
2. 进入块级作用域后的预编译
当代码执行到{}这个块级作用域时,引擎会单独扫描这个块的内容:
- 块内的
function foo()会被完全提升到块的顶部(声明+赋值,和函数作用域里的普通函数提升逻辑一致),所以在块内的第一个console.log("2:"+foo)就能直接拿到foo函数本身,输出2:function foo(){ console.log("checked"); }。 - 当执行到
function foo(){...}这行代码时,本质是再次给块内的foo赋值(和预编译时的赋值是同一个函数,所以没有变化),所以第三个console.log("3:"+foo)依然输出函数本身。
3. 块级作用域执行完毕后
当块内代码执行完成,非严格模式下,块级函数会被赋值给外层作用域(这里是全局)的同名变量,所以此时全局的foo从undefined变成了foo函数本身,最后一个console.log("4:"+foo)就输出函数内容了。
补充个小细节:如果是在严格模式下,块级函数只会被提升到块内的顶部,外层作用域不会提前创建foo变量,此时第一个console.log会直接抛出ReferenceError,这是严格模式和非严格模式的关键区别。
内容的提问来源于stack exchange,提问作者MaximPro
相关产品推荐
相关产品推荐

