ES6 | 块级作用域中函数声明后,产生的微妙变化?

284 阅读2分钟

首先提出一个问题:

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)

函数声明在块级作用域中的另一特点

  1. 函数声明可以变量提升到块级作用域的最上方

于是最开始的代码就变成了上面这样

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行代码的输出结果

  1. 此时function变量提升至块级作用域最上方,所以此时打印的a为function
  2. 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行代码时

  1. 将函数体的作用域同步到函数名,此时function的作用域为window,a的值为1
  2. 在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

总结

在块级作用域中函数声明,会将函数的作用域同步到函数名,即在作用域下创建函数名,并将值同步