我正在参加「掘金·启航计划」
无意中看到如下的代码题目:
var a;
if(true){
console.log(a);
a = 5;
function a(){};
function b(){};
a = 0;
console.log(a);
}
console.log(a);
console.log(b);
相比较于ES5,ES6的let为JavaScript新增了块级作用域,即代码中每一层都是单独的作用域,内层定义域可以定义外层作用域内的同名变量。在ES5中,函数只能在顶层作用域和函数作用域之中声明,而在ES6中,明确允许在块级作用域之中声明函数,在块级作用域之中,函数声明语句的行为类似于let,在块级作用域之外不可引用。但是,由于需要实现兼容性问题,所以规定浏览器(针对于支持ES6版本的浏览器)可以不遵循上述规定,将函数声明类比为var,会提升到全局作用域或函数作用域的头部。
所以按照上述说法,实际运行的代码如下:
var a = undefined;
var b = undefined;
var a;
if(true){
function a(){};
function b(){};
console.log(a);//funciton a
a = 5;
function a(){};
function b(){};
a = 0;
console.log(a);
}
console.log(a);
console.log(b);
所以第一个console a输出函数定义没有问题,当执行a = 5的时候,块内的默认变量被赋值,因为此时执行给a赋值的过程中,会查找作用域链有没有声明a,刚好函数声明提升到了顶部,所以块内的a被赋值了,而此时window.a没有被赋值依然为undefined。在执行下方的function a(){};的时候,块外跟块内函数声明同名的变量只有在函数声明那段代码执行后才会赋值,所以执行完9行代码的时候window.a被赋值。
在执行11行的a = 0;时,赋值作用域寻找到块内作用域进行赋值操作,所以12行的输出为0;块内作用域执行完后,最后两行的输出语句中的变量会寻找全局作用域的变量即window.a,window.b,而此时的window.a为5,window.b为function() { }。