块级作用域里的代码运行
先上一道面试题
var a= 0
if(true){
console.log(a); //[Function: a]
a = 1
console.log(a); //1
function a(){}
a = 2
console.log(a); //2
}
console.log(a); //1
看到这里是不是觉得自己的脑子不够用了,这运行结果为什么这么奇怪。不过没关系,你看完了本片文章,你就会觉得这题也不过如此。下面就跟着我的节奏一起来尝试去解析这道面试题吧,为自己增加面试知识点
前言
JS中作用域有:全局作用域、函数作用域。没有块级作用域的概念。但是ES6中新增了块级作用域。块作用域由 { } 包括,if语句和for语句里面的{ }也属于块作用域。
块级作用域
ES6中说明了块级作用域可通过新增命令let和const声明,所声明的变量在指定块的作用域外无法被访问。块级作用域在如下情况被创建:
- 在一个函数内部
- 在一个代码块(由一对花括号包裹)内部
为什么要新增块级作用域
ES6之前没有块级作用域之前会出现下面的一些情况
- 在if或者for语句里面声明的变量会提升成全局作用域
for(var i=0;i<=5;i++){
console.log("hello");
}
console.log(i); //6
- 块级作用域里面用let和const声明的变量就不会被外部访问到
解析
var a= 0
if(true){
console.log(a);
a = 1
console.log(a);
function a(){}
a = 2
console.log(a);
}
console.log(a);
在块级作用域里面有函数的声明,函数的声明就是先进行函数名的声明,然后在进行函数体的赋值
- 代码就等同于下面
var a= 0
if(true){
var a
a = function(){}
console.log(a);
a = 1
console.log(a);
// function a(){}
a = 2
console.log(a);
}
console.log(a);
块级作用域里面var声明的变量会提升到块级作用域的上一级非块级作用域的最顶部
var a
var a= 0
if(true){
a = function(){}
console.log(a); //[Function: a]
a = 1
console.log(a); //1
// function a(){}
a = 2
console.log(a);
}
console.log(a);
现在开始执行代码,所以第一个打印的就是函数,然后执行 a = 1
将1赋值给块级作用域里面的a,第二个打印的就是1.然后开始执行function a(){}
- 重点来了!!! 在if或则for语句里面定义的函数,函数名变量会同步到和函数同一个作用域下 此时块级作用域里面的变量a的值为1,同步到和函数同一作用域下,函数的作用域是windows下的全局作用域,所以全局中的a的值被同步为1
var a= 0 //a = 1
if(true){
// a = 1
console.log(a); //[Function: a]
a = 1
console.log(a); //1
function a(){}
a = 2
console.log(a);
}
console.log(a);
继续往下走,执行代码 a = 2
将2赋值给块级作用域里面的 a,第三个打印的就是2 ,最后一个打印的就是全局作用域中的a,为 1。看到这里,你应该懂了吧。没懂得话还可以看下面的练习题
练习
var a = 0
if (true) {
console.log(a);
function a() {}
a = 1
console.log(a);
function b() {}
}
console.log(a);
console.log(b);
按照之前的讲解的,块级作用域里面的函数名变量声明会被提升到块级作用域上一级非块级作用域的最顶端,函数体的赋值会提升到块级作用域的最顶端
var a
var b
var a = 0
console.log(a);
if (true) {
a = function (){}
b = function (){}
console.log(a);
// function a() {}
a = 1
console.log(a);
// function b() {}
}
console.log(a);
console.log(b);
代码开始执行,第一个打印的就是0。第二个打印的就是[Function: a]
。然后执行代码function a() {}
将函数变量名同步到函数的同意作用域下,也就是全局的变量a的值被同步为 function a() {}
,执行 a = 1
,继续往下执行,第三个打印的就是 1。执行 function b() {}
思想同上,最后的两个打印全局变量a和b 结果为[Function: a]
、[Function: b]
var a = 0
console.log(a); // 0
if (true) {
console.log(a); // [Function: a]
function a() {}
a = 1
console.log(a); // 1
function b() {}
}
console.log(a); // [Function: a]
总结
- 块级作用域里面var声明的变量会提升到块级作用域的上一级非块级作用域的最顶部
- 在块级作用域里面声明函数,函数名变量会同步到和函数同意作用域下