JavaScript ES6中的简写语法总结与使用技巧(14)

let topmost = {}
{
 let inner = {}
 {
  let innermost = {}
 }
 // attempts to access innermost here would throw
}
// attempts to access inner here would throw
// attempts to access innermost here would throw

在for循环中使用let是一个很好的实践,这样定义的变量只会在当前块作用域内生效。

for (let i = 0; i < 2; i++) {
 console.log(i)
 // <- 0
 // <- 1
}
console.log(i)
// <- i is not defined

考虑到let声明的变量在每一次循环的过程中都重复声明,这在处理异步函数时就很有效,不会发生使用var时产生的诡异的结果,我们看一个具体的例子。

我们先看看 var 声明的变量是怎么工作的,下述代码中 i变量 被绑定在 printNumber 函数作用域中,当每个回调函数被调用时,它的值会逐步升到10,但是当每个回调函数运行时(每100us),此时的i的值已经是10了,因此每次打印的结果都是10.

function printNumbers() {
 for (var i = 0; i < 10; i++) {
  setTimeout(function () {
   console.log(i)
  }, i * 100)
 }
}
printNumbers()

使用let,则会把i绑定到每一个块作用域中。每一次循环 i 的值还是在增加,但是每次其实都是创建了一个新的 i ,不同的 i 之间不会相互影响 ,因此打印出的就是预想的0到9了。

function printNumbers() {
 for (let i = 0; i < 10; i++) {
  setTimeout(function () {
   console.log(i)
  }, i * 100)
 }
}
printNumbers()

为了细致的讲述let的工作原理, 我们还需要弄懂一个名为 Temporal Dead Zone 的概念。

Temporal Dead Zone
简言之,如果你的代码类似下面这样,就会报错。即在某个作用域中,在let声明之前调用了let声明的变量,导致的问题就是由于,Temporal Dead Zone(TDZ)的存在。

{
 console.log(name)
 // <- ReferenceError: name is not defined
 let name = 'Stephen Hawking'
}

如果定义的是一个函数,函数中引用了name变量则是可以的,但是这个函数并未在声明前执行则不会报错。如果let声明之前就调用了该函数,同样会导致TDZ。

// 不会报错
function readName() {
 return name
}
let name = 'Stephen Hawking'
console.log(readName())
// <- 'Stephen Hawking'
// 会报错
function readName() {
 return name
}
console.log(readName())
// ReferenceError: name is not defined
let name = 'Stephen Hawking'

即使像下面这样let定义的变量没有被赋值,下面的代码也会报错,原因依旧是它试图在声明前访问一个被let定义的变量

function readName() {
 return name
}
console.log(readName())
// ReferenceError: name is not defined
let name
      

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:http://www.heiqu.com/265.html