首先提出一个问题:
Es6之前有块级作用域吗?
当然有, { } 就是一个块级作用域
那么来看以下代码:
var a = 0
if (true) {
a = 1
function a() {}
a = 2
console.log('里面', a);
}
console.log('外面', a)
它的输出结果是:
里面, 2
外面, 1
是不是很惊讶,我们现在逐步拆解,来分析函数声明在块级作用域中干了什么?
首先需要了解一个很重要的知识:在块级作用域中定义函数时,会将函数的作用域同步到函数名
var a = 0
if (true) {
function a(){}
a = 1
a = 2
console.log('里面', a);
}
console.log('外面', a)
函数声明在块级作用域中的另一特点
- 函数声明可以变量提升到块级作用域的最上方
于是最开始的代码就变成了上面这样
var a = 0
if (true) {
console.log(a, window.a); // fun, 0
a = 1
function a(){}
a = 2
console.log('里面', a);
}
console.log('外面', a)
我们来分析第3行代码的输出结果
- 此时function变量提升至块级作用域最上方,所以此时打印的a为function
- window下的a,就是全局作用域的a为0
var a = 0
if (true) {
console.log(a, window.a); // fun, 0
a = 1 // fun = 1
function a() {}
a = 2
console.log('里面', a);
}
console.log('外面', a)
第4行代码 把此时function a()又赋值成了1
var a = 0
if (true) {
console.log(a, window.a); // fun, 0
a = 1 // fun = 1
function a() {}
a = 2
console.log('里面', a);
}
console.log('外面', a)
执行第5行代码时
- 将函数体的作用域同步到函数名,此时function的作用域为window,a的值为1
- 在window作用域下将a的值改为1-- 即
var a = 1
var a = 1
if (true) {
console.log(a, window.a); // fun, 0
a = 1 // fun = 1
function a() {}
a = 2
console.log('里面', a);
}
console.log('外面', a)
执行第6行代码 将块级作用域中的a改为2
所以最后输出结果为 2, 1
总结
在块级作用域中函数声明,会将函数的作用域同步到函数名,即在作用域下创建函数名,并将值同步