js-ES6學習筆記-let命令

一、let命令

  ES6新增了let命令,用來聲明變量。它的用法相似於var,可是所聲明的變量,只let命令所在的代碼塊內有效。安全

  for循環的計數器,就很合適使用let命令。閉包

  下面的代碼若是使用var,最後輸出的是10函數

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

  上面代碼中,變量ivar聲明的,在全局範圍內都有效。因此每一次循環,新的i值都會覆蓋舊值,致使最後輸出的是最後一輪的i的值。(常見於閉包的考察)spa

  若是使用let,聲明的變量僅在塊級做用域內有效,最後輸出的是6。code

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

  上面代碼中,變量ilet聲明的,當前的i只在本輪循環有效,因此每一次循環的i其實都是一個新的變量,因此最後輸出的是6blog

  JavaScript 引擎內部會記住上一輪循環的值,初始化本輪的變量i時,就在上一輪循環的基礎上進行計算。ip

  另外,for循環還有一個特別之處,就是循環語句部分是一個父做用域,而循環體內部是一個單獨的子做用域內存

  不存在變量提高

  var命令會發生」變量提高「現象,即變量能夠在聲明以前使用,值爲undefined。這種現象多多少少是有些奇怪的,按照通常的邏輯,變量應該在聲明語句以後纔可使用。作用域

爲了糾正這種現象,let命令改變了語法行爲,它所聲明的變量必定要在聲明後使用,不然報錯io

  暫時性死區

  只要塊級做用域內存在let命令,它所聲明的變量就「綁定」(binding)這個區域,再也不受外部的影響。

  ES6明確規定,若是區塊中存在letconst命令,這個區塊對這些命令聲明的變量,從一開始就造成了封閉做用域。凡是在聲明以前就使用這些變量,就會報錯

  總之,在代碼塊內,使用let命令聲明變量以前,該變量都是不可用的。這在語法上,稱爲「暫時性死區」(temporal dead zone,簡稱 TDZ)。

  「暫時性死區」也意味着typeof再也不是一個百分之百安全的操做(會使typeof報錯)。

  總之,暫時性死區的本質就是,只要一進入當前做用域,所要使用的變量就已經存在了,可是不可獲取,只有等到聲明變量的那一行代碼出現,才能夠獲取和使用該變量。

  不容許重複聲明

  let不容許在相同做用域內,重複聲明同一個變量

二、塊級做用域

  ES5只有全局做用域和函數做用域,沒有塊級做用域,這帶來不少不合理的場景。

  第一種場景,內層變量可能會覆蓋外層變量。

  第二種場景,用來計數的循環變量泄露爲全局變量。

  let實際上爲JavaScript新增了塊級做用域。

function f1() {
  let n = 5;
  if (true) {
    let n = 10;
  }
  console.log(n); // 5
}

  上面的函數有兩個代碼塊,都聲明瞭變量n,運行後輸出5。這表示外層代碼塊不受內層代碼塊的影響。若是使用var定義變量n,最後輸出的值就是10。

  塊級做用域的出現,實際上使得得到普遍應用的當即執行函數表達式(IIFE)再也不必要了。

// IIFE 寫法
(function () {
  var tmp = ...;
  ...
}());

// 塊級做用域寫法
{
  let tmp = ...;
  ...
}

  塊級做用域與函數聲明

  ES5 規定,函數只能在頂層做用域和函數做用域之中聲明,不能在塊級做用域聲明。

  ES6 引入了塊級做用域,明確容許在塊級做用域之中聲明函數。

  ES6 規定,塊級做用域之中,函數聲明語句的行爲相似於let,在塊級做用域以外不可引用。

  考慮到環境致使的行爲差別太大,應該避免在塊級做用域內聲明函數。若是確實須要,也應該寫成函數表達式,而不是函數聲明語句。

相關文章
相關標籤/搜索