1.var声明与变量提升

使用var关键字声明的变量,无论其实际声明位置在何处,都会被视为声明于函数的顶部(如果声明不在函数内,则视为全局作用域的顶部),这就是所谓的变量提升,例子如下:
image.png
注:value变量的声明会被提升到函数的顶部,而初始化赋值操作则留在了原地,这代表在else分支内也可以正确的访问value变量而不会报错。

2.块级声明

注:块级声明就是让所声明的变量不能在块级作用域外进行访问,块级作用域又被称为词法作用域,在如下的情况下会被创建:
1.在一个函数内部
2.在一个由一对花括号包裹的代码块内部({})

let声明

let声明的语法与var的语法一致,但let会将变量的作用域限制在当前的代码块中。let声明并不会被提升,因些若想在变量在整个代码块内部可以使用,需手动将let声明放置到代码块的顶部。如var例子修改为let后:
image.png

禁止重复声明

如果在代码块内部一个标识符已被定义,那么在此代码块中使用同一个标识符进行let声明则会报错。

常量声明

使用const声明的变量被认为是常量,常量的值在被初始化后过后是不可修改,所有const声明的变量必须在声明时进行初始化操作。

对比常量声明与let声明

相同点:

  1. - 在代码块内使用letconst声明都不允许在代码块外部进行使用,即声明不会被提升。
  2. - 如在代码块内部一个标识符已被定义,那么在些代码块中letconst则不能对这个标识符进行声明,否则则会报错处理。

不同点:

  1. - let声明赋值后可修改,const声明赋值后不可修改(注:const声明的对象可修改,因对象为引用类型)。

使用const声明对象

const声明会阻止对于变量绑定及变量自身值的修改,但不会阻止变量成员的修改。

暂时性死区(TDZ)

使用let和const声明的变量,在达到声明位置之前都是无法访问的,如果试图访问会导致报错,在达到声明位置之前无法被访问的区域被称为暂时性死区。
当JS引擎扫描代码块并发现变量声明时,它会处理var声明时将声明提升到函数的顶部,而let和const则会将声明放入暂时性死区。任何在暂时性死区访问let和const声明的变量时就会导致报错。只有执行到了let和const声明后,该变量才会从暂时性死区内被移除,才可以安全使用。

3.循环中的块级绑定

循环中的块级绑定

image.png
如上图,开发者或许最期望在for循环内使用块级作用域,也就是想让一次性的循环计数器仅能在for循环内部使用。但这个例子在其他默认使用块级作用域语言中能够按照预期工作,也就是在for循环中能访问到变量i,但在JS中,var声明导致了变量提升,循环结束后,依旧可以在循环体外部访问到变量i,如果把var改为使用let声明的话,就会看到循环后,无法在循环外部访问到变量i

4.全局块级绑定

在全局作用域 中,如window已存在需要声明的标识符,在使用var声明时,会覆盖window中已经存在的标识符,如果使用let或const声明则会在全局作用域上创建新的绑定,但不会有任何属性加到全局对象上,这也就意味着使用let或const不会覆盖一个全局变量,你只能将其遮蔽。
image.png

5.块级绑定新的最佳实践

默认情况 下应使用let代替var声明,如遇到需要受保护的变量则使用const声明。

6.总结

let与const块级绑定将词法作用域引入了JS,这种声明方式都不能进行变量提升,并且仅在它们的代码块内部可用。这样变量就可以在必要位置被准确声明。let与const有一个副作用,就是不能在变量声明位置之前访问它们,由于块级绑定存在暂时性死区,试图在声明位置之前访问它就会导致报错。