let關(guān)鍵字

1. 作用域

let關(guān)鍵字:引入let的原因正是var的局限性.

相比于var,let有以下幾點優(yōu)勢:

  • 作用域

    var的作用域是會提升的,var聲明的變量只能是全局的或者是整個函數(shù)塊的

    let則允許聲明一個作用域被限制在塊級中的變量、語句或者表達式。

for(var i = 0; i < 5; i++) {
}
console.log(i);

分析 :上面代碼中使用的是var ,那么最終的輸出結(jié)果將會是5,因為i雖然在for循環(huán)中聲明的,但是作用域會被提升到函數(shù)塊的邊界或者直至全局

? 但是如果使用的是let,將會報錯,會顯示i is not define ,原因就是聲明的i被局限于for循環(huán)這個塊中,出了這個快就找不到i這個變量了,

? 需要注意的是,在程序的頂層,let并不會向var那樣將聲明的變量加到全局對象上去

//控制臺輸出結(jié)果
var i = 5
undefined
this.i
5
let y = 5
undefined
this.y
undefined

2. 對let塊級作用域的使用:

如果使用var來定義循環(huán)控制變量

var lis = document.querySelector('.test').querySelectorAll('li');
  for(var i = 0 ; i<lis.length;i++){
    lis[i].onclick = function (event) {
       console.log(i);
    }
  }
//點擊li時輸出的結(jié)果都相同的,都是li的個數(shù)

如果使用let

var lis = document.querySelector('.test').querySelectorAll('li');
for (let i = 0; i < lis.length; i++) {
      lis[i].onclick = function (event) {
        console.log(i);
      }
  }
//點擊li時輸出的結(jié)果,為每個li標(biāo)簽的索引

分析

? var 聲明的i對應(yīng)的是全局變量,也就是說i是在循環(huán)之外存在的。所以每次點擊都對應(yīng)同一個i,而i是全局的,所以在循環(huán)結(jié)束后,i的值就已經(jīng)確定了,因此每次點擊出來的都是一樣的。

? 但是如果使用了let,那么使用的將是塊級作用域,也就是說,每個點擊事件都會進入一個不同的塊,所以每個點擊都會輸出正確的序號。

模仿私有接口

在處理構(gòu)造函數(shù)的時候,可以通過let綁定來共享一個或多個私有成員,而不使用閉包

let暫存死區(qū)的錯誤

在相同的函數(shù)或塊作用域內(nèi)重新聲明同一個變量會引發(fā)SyntaxError

if (x) {
  let foo;
  let foo; // TypeError thrown.
}
//重復(fù)聲明報錯,但是var不會報錯

let在包含聲明的作用域頂部被創(chuàng)建,通常這種被叫做“變量提升”。但和var不同的是,var的創(chuàng)建會設(shè)置一個初試的undefined值,let變量在沒有運行到聲明代碼時是不會被初始化的。引用它將會導(dǎo)致 ReferenceError(而使用 var聲明變量則恰恰相反,該變量的值是 undefined )。直到初始化執(zhí)行的時候,該變量都處于從塊開始到初始化處理的“暫存死區(qū)”。

//暫存死區(qū)
function do_something() {
   console.log(x);  //undefined
   console.log(y);  //Uncaught ReferenceError: y is not defined
   var x = 1;
   let y = 2;
}
do_something();

switch 聲明中你可能會遇到這樣的錯誤,因為它只有一個塊.

switch (x) {
  case 0:
    let foo;
    break;
    
  case 1:
    let foo; // TypeError for redeclaration.
    break;
}

但是,重要的是要指出嵌套在case子句內(nèi)的塊將創(chuàng)建一個新的塊作用域的詞法環(huán)境,這不會產(chǎn)生上面顯示的重新聲明錯誤。

let x = 1;

switch(x) {
  case 0: {
    let foo;
    break;
  }  
  case 1: {
    let foo;
    break;
  }
}

與詞法作用域結(jié)合的暫存死區(qū)

由于詞法作用域,表達式(foo + 55)內(nèi)的標(biāo)識符“foo”會解析為if塊的foo,而不是覆蓋值為33的foo。在這一行中,if塊的“foo”已經(jīng)在詞法環(huán)境中創(chuàng)建,但尚未達到(并終止)其初始化(這是語句本身的一部分):它仍處于暫存死區(qū)。

function test(){
   var foo = 33;
   if (true) {
      let foo = (foo + 55); // ReferenceError
   }
}
test();

這種現(xiàn)象可能會使您陷入以下情況。指令let n of n.a已經(jīng)在for循環(huán)塊的私有范圍內(nèi),因此標(biāo)識符“n.a”被解析為位于指令本身的第一部分(“l(fā)et n”)中的'n'對象的屬性'a' ,由于尚未達成和終止其聲明,因此仍處于暫存死區(qū)。

function go(n) {
// n here is defined!
  console.log(n); // Object {a: [1,2,3]}

  for (let n of n.a) { // ReferenceError
    console.log(n);
  }
}
go({a: [1, 2, 3]});

其他情況

當(dāng)在塊中使用時,let將變量的作用域限制為該塊。注意**var**的作用域在它被聲明的函數(shù)內(nèi)的區(qū)別。

var a = 1;
var b = 2;

if (a === 1) {
  var a = 11; // the scope is global
  let b = 22; // the scope is inside the if-block
  console.log(a);  // 11
  console.log(b);  // 22
} 
console.log(a); // 11
console.log(b); // 2
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容