let、const和块级作用域

函数作用域

作用域,顾名思义就是一套规则,用于确定在何处(哪个作用域中),如何查找变量的规则(遵循作用域链)。

ES6以前,javascript只有两种作用域,全局作用域和函数作用域,也有人叫本地作用域。

函数作用域在带来便利的同时,也会造成一些匪夷所思的错误。

var a = []
for(var i = 0; i < 10; i++) {
  a[i] = function () {
    console.log(i)
  }
}

a[2]() // 10
a[6]() // 10

这里,我们通过var声明了i变量,js只有函数作用域,自然i是在全局范围内都有效的变量。for循环语句内每次循环,
i的值都会加1,直到i等于10后跳出循环。循环内有一个匿名函数,每次循环均打印出i,这里的i与全局下的i建立了引用关系。
导致函数推出后,i的值仍然存在。循环完成后的i = 10,所以无论如何调用都返回10。

这是很不符合直觉的,因为我们写了循环,通常就只想在for循环内部的上下文中使用变量i,但实际上i可以在全局作用域下访问,
污染了全局作用域。

块级作用域

let

ES6引入了let关键字,可以将变量绑定在它所处的任意作用域内(一般是{...}内),实现块级作用域。

这么做的意义在于,避免因为变量提升导致外层作用域读取内层作用域的变量,其次,内层变量无法覆盖外层变量。

在代码块({...})中使用let声明变量,那么变量便会陷入「暂时性死区」,即在使用let声明的块级作用域内,他所声明的变量就绑定在这个区域中,不再受外部影响,
而区域内阻止变量被访问(否则报错),除非访问行为发生在声明语句之后。

var apple = 123

if(true) {
  // apple = 321 // Uncaught ReferenceError
    let apple = 321
    console.log(apple) // 321
    apple = 'banana'
    console.log(apple) // banana
}

let的其它特性

  1. 不允许重复声明:通过var重复声明变量,不会发生报错,且后声明的会覆盖前面的。而用let重复声明则会报错;
  2. 不允许变量提升
    javascript console.log(bar); // 报错ReferenceError let bar = 2;

const

const声明一个只读的常量,一旦声明了,它的值不能改变。它拥有一些和let类似的特性,具体如下:

  1. 一旦声明,常量的值就不得改变,否则报错,且声明的同时必须完成初始化;
  2. 声明后,变量同样会绑定块级作用域,仅在块级内有效;
  3. 声明的变量不提升,同样存在暂时性死区;
  4. 不可重复声明;

const保证的并不是变量的值不被改变,而是变量指向的内存地址不得改动。因此,对于简单类型的数据,
值值就保存在变量指向的那个内存地址,因此等同于常量。但对于复合类型的数据(主要是对象和数组),变量指向的内存地址,保存的只是一个指针,const只能保证这个指针是固定的,至于它指向的数据结构是不是可变的,就完全不能控制了。

猜你喜欢

转载自www.cnblogs.com/CharmanderS5/p/9077343.html
今日推荐