1. 程式人生 > >var 與let/const 變數提升與TDZ

var 與let/const 變數提升與TDZ

我們都知道,在ES5及以前,var關鍵字被用來定義變數,但是到了ES6,就開始使用let/const來定義變數或者常量。那麼這兩者到底有什麼區別呢?

  1. var遵循函式作用域,let/const遵循塊級作用域;
  2. 由於變數提升,var關鍵字定義的變數在申明之前可以訪問,但得到undefined, let/const關鍵字定義的變數在申明之前訪問會丟擲ReferenceError的錯誤。

第一點沒什麼可講的,作用域不同而已。下面主要來談談第二點。那麼為什麼 let/const關鍵字定義的變數在申明之前不能被訪問呢,它是不是沒有進行變數提升呢?

根據ES6標準中對於let/const宣告的章節13.3.1

let/const宣告,有以下的文字說明:

The variables are created when their containing Lexical Environment is instantiated but may not be accessed in any way until the variable’s LexicalBinding is evaluated.
也就是說其實let/const申明的變數,js引擎對其進行預編譯時也會進行變數提升(hoist),但是這時候並沒有進行詞法繫結,也就是對宣告語句進行求值運算,是不可以被訪問的,訪問就會丟擲錯誤,這也被稱為暫時性死區(TDZ),如以下程式碼段:
let total = 0;
function func(num1, num2) {
      console.log(total);   //出現TDZ,訪問丟擲ReferenceError錯誤
      let total = num1 + num2;
      console.log(total);
  }
func(100 , 200);
console.log(total);

在這裡插入圖片描述
那麼這時如果把let換成var呢,會出現什麼現象呢?

var total = 0;
function func(num1, num2) {
      console.log(total);  
      var total = num1 + num2;
      console.log(total);
  }
func(100 , 200);
console.log(total);

在這裡插入圖片描述
也就是變數的查詢會先在區域性作用域內進行,如果沒有,才會追溯到上級作用域。由於變數提升的作用,func函式內第一次列印total會打印出undefined, 而不是0,也並不會丟擲任何錯誤。

總結:養成良好的程式碼習慣,變數的使用遵循先宣告再使用的規則,就不會遇到這些問題。