ES6 let, var 差異比較

xxlee (Ching Hung Lee)
Practicode
Published in
5 min readMay 24, 2017

剛接觸 ES6 時,最容易發現的差異是以前熟悉的變數宣告關鍵字 var,全部都被替換成了 let,兩者之間到底有什麼差別呢?在這篇文章會將彼此間的差異做一個整理。

1. 新的作用域

在 ES6 之前,想要宣告區域變數 (local variable),唯一的方法只有開一個 function 在裡面宣告。

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

在上面的程式碼中,預期應該要印出99,然而 var 只要不在 function 內就具有全局作用域,整個程式碼會共同一個 i ,重複宣告會蓋過之前的值,並且不會有語法錯誤。

然而現今 javascript 早已不限於簡單的網頁腳本,這樣的作用域規範顯得不敷使用,對於物件導向的設計也礙手礙腳。

有鑑於此,在 ES6 中引入了新的關鍵字 let ,和新的作用域 “區塊(block)”,可以為乾淨的大括號 (如下例),或帶有 label (for、if …)。

{
let message = "U can't C me!";
console.log(message); // U can't C me!
}
console.log(message); // ReferenceError: message is not defined

此例中變數 message 的作用域只在大括號的範圍內,若將let 改成var ,在 log 裡則會看到兩行相同的字串。

2. 不同的 lifecycle

考慮以下程式碼:

{
console.log(a); // undefined
var a = 1;
}
{
console.log(b); // ReferenceError: b is not defined
let b = 1;
}

造成此結果的原因可分為兩步驟,首先,由於 javascript 在執行時會將所有的變數和函式宣告 ”提升 (hoist)” 至 block 的最頂端 (這也是為什麼無論在哪宣告 function 都能正常使用的原因),也就是說這段程式碼同義於:

{
var a;
console.log(a); // undefined
a = 1;
}
{
let b;
console.log(b); // ReferenceError: b is not defined
b = 1;
}

接下來,由於兩者的 lifecycle 不同,使用 let 宣告的變數在未賦值時被呼叫時會 throw ReferenceError,而使用 var 則會直接印出 undefined。關於兩者詳細的 lifecycle 差別可以參考 這篇文章

3. 迴圈內重新綁定 (bind)

先看範例:

for (var i = 0; i < 5; i++) {
setTimeout(function(){
console.log(`Hi I'm No.${i}!`); // 印出 'Hi I'm No.5!' 五次
}, 100);
}

在此例中,每個閉包 (closure) 共享了同一個 i ,造成在 0.1 秒過後要印出第一個值時,迴圈早已跑完,而此時的i 為 5,並不再更動。將上例中的var 改為let ,則因為每個閉包都會綁定不同的i ,讓五兄弟終於可以團圓了。附帶一提,由於每次都需要綁定,在迴圈迭帶次數大時會感受到彼此間的速度差異。

4. 重複宣告會造成語法錯誤

在過去使用 var時,若重複宣告變數,則會無視後者的宣告,僅重新賦值給它。但使用 let 重複宣告則會 throw SyntaxError,這項特性有助於檢查程式中的小 bug。

let x = 1;
let x = 2; // SyntaxError: Identifier 'x' has already been declared

5. 不是全域個體 (global object) 的屬性

在瀏覽器運行的 javascript 之全域個體一律為 window ,然而在全域範圍使用let宣告,實際上是存在於一個看不見的作用域中的區域變數。

var x = 1;
console.log(window.x); // 1
let y = 2;
console.log(window.y) // undefined

該棄用 var 嗎?

我的回答是:是。

這也是網路上大多人的回答,然而仍然存在一些擁護 var 的人,理由包括相容性 (現今的瀏覽器幾乎都能支援 let,可以參考 Can I Use)、修改舊有程式碼可能出錯等,有興趣可以參考這個知乎討論串

參考資料

--

--