ES6 let声明之变量提升,块级作用域,计数器变量,函数声明
在ES5中,只存在全局作用域和函数作用域。而且var声明存在变量提升的问题。这是非常不合理的。
这个函数会输出什么?test? hello world? 不不不,是undefined。因为ES5中没有块级作用域,而且存在变量提升的问题。这个函数实际上的执行如下代码
这是由于变量提升导致的内层变量覆盖了外层的变量。
什么是变量提升?
变量可以在声明之前使用,值为undefined。这就是变量提升。
let声明不存在变量提升:let 声明的变量必须要在声明之后使用,否则就会报错。
let声明不存在变量提升的原理:暂时性死区
只要作用域中存在let声明,那么这个变量就会绑定这个区域。同时,这个区域会变成一个块级作用域。只要这个区域中存在let声明,那么let声明的变量就会被存放在暂时性死区(TDZ)中,直到这个变量被声明,才会被拿出来。使用TDZ中的变量会报错。
块级作用域
for循环中使用var声明产生的问题:1.计数变量泄露成全局变量,2.计数变量共用
1.
2.
(这里面牵扯到异步函数的执行顺序问题,在这里简单介绍下就是:setTimeout是个异步函数,使得console.log(i)在最后才被调用,这个时候,for循环结束,同时执行了一次i++,这个时候 i =5 全局只存在一个公用 i ,所以输出5个5)。
使用let作为计数变量是完美的。
使用let声明后,i 只在本轮循环有效,相当于每一轮都会重新声明一个 i。而且JS引擎会记住上一轮的 i。
所以,尽情使用let 到你的for循环中吧。
块级作用域中的函数声明
来看这样一个函数声明
在ES5环境下,运行的输出 “insede”. ES5实际执行的代码如下
而在ES6环境下执行的是这样的:
阮一峰老师总结的很好:在ES6中
1.允许在块级作用域中声明函数
2.函数声明类似于var,会提升函数声明到全局作用域或者函数作用域头部。(函数声明并不是类似于let,因为这样的话会对旧版代码产生很大影响,为了减轻兼容性问题。)
3.函数声明还会提升到所在块级作用域头部
总的来说,因为存在很大兼容性问题,应该减少使用块级作用域中声明函数。或者使用函数表达式形式,而不是函数声明语句。