块级作用域内函数和变量声明
为了方便后续引用理论依据进行说明,这里先给一些依据进行编号
- 允许在块级作用域内声明函数
- 函数声明类似于 var,即会提升到全局作用域或函数作用域的头部
- 同时,函数声明还会提升到所在的块级作用域的头部
- var 命令和 function 命令声明的全局变量,依旧是顶层对象的属性
- let 命令、const 命令、class 命令声明的全局变量,不属于顶层对象的属性。
从 4、5 两点看出,从 ES6 开始,全局变量将逐步与顶层对象的属性脱钩。在以前,顶层对象的属性赋值与全局变量的赋值,是同一件事
本文代码测试均在谷歌浏览器(版本: 80.0.3987.149)测试,支持 es6 语法,其余浏览器执行结果可能会有所不同,不代表所有浏览器的结果。防止代码相互影响,测试均是在新的空 tab 下进行。
1. 块级作用域内的变量声明
测试代码和结果
一些猜测
-
在 es6 中,直接给之前没有声明的变量赋值,会沿着作用域链一直查找,一直到顶级对象,然后进行赋值
-
在顶级对象上都没找到属性时,会报错。
猜测实际运行代码以及结果
如果存在 var 声明,结果就和之前的不太一样了
猜测实际执行代码和测试结果
解析
-
因为 var 声明会被提前,所以相当于在代码顶部添加了一段声明
-
根据依据 4,var 声明的全局变量,其实就是顶层对象的属性。所以这里不管是打印 a 还是 window.a ,其实最后通过作用域链找到的都是 window.a
另外一个验证测试
如果整个过程发生在函数内呢?
这个结果还是比较符合预期的
-
通过 var 声明时,声明被提升到函数顶部,然后真实赋值时,通过作用域链找到函数内的变量 a,所以后续打印 a 为 1,而 window.a 为 undefined
-
没有 var 命令时,赋值操作通过作用域链找到的是全局作用域,所以赋值在了全局,然后不管打印 a 还是 window.a 最后找到的都是 window.a