使用 var 關鍵字聲明的變量,不管其實際聲明位置在何處,都會被視爲聲明於所在函數的頂部,若是聲明不在任意函數內,則視爲在全局做用域的頂部。瀏覽器
function getValue(condition) { if (condition) { var value = "blue"; // 其餘代碼 return value; } else { // value 在此處可訪問,值爲 undefined return null; } // value 在此處可訪問,值爲 undefined } 複製代碼
若是你不太熟悉 JS ,或許會認爲僅當 condition 的值爲 true 時,變量 value 纔會被建立。但實際上,value 不管如何都會被建立。 JS 引擎在後臺對 getValue 函數進行了調整, 就像這樣:安全
function getValue(condition) { var value; if (condition) { value = "blue"; // 其餘代碼 return value; } else { return null; } } 複製代碼
value 變量的聲明被提高到了頂部,而初始化工做則保留在原處。這意味着在 else 分支內 value 變量也是可訪問的,此處它的值會是 undefined ,由於它並無被初始化。bash
塊級聲明也就是讓所聲明的變量在指定塊的做用域外沒法被訪問(在一個函數內部 或 在一個代碼塊內部)。markdown
let 聲明的語法與 var 的語法一致。你基本上能夠用 let 來代替 var 進行變量聲明,但會將變量的做用域限制在當前代碼塊中(其餘細微差異會在稍後討論)。因爲 let 聲明並不會被提高到當前代碼塊的頂部,所以你須要手動將 let 聲明放置到頂部,以便讓變量在整個代碼塊內部可用。併發
function getValue(condition) { if (condition) { let value = "blue"; // 其餘代碼 return value; } else { // value 在此處不可用 return null; } // value 在此處不可用 } 複製代碼
若是一個標識符已經在代碼塊內部被定義,那麼在此代碼塊內使用同一個標識符進行 let 聲明就會致使拋出錯誤。函數
var count = 30; // 語法錯誤 let count = 40; 複製代碼
在嵌套的做用域內使用 let 聲明一個同名的新變量,則不會拋出錯誤。spa
var count = 30; // 不會拋出錯誤 if (condition) { let count = 40; // 其餘代碼 } 複製代碼
ES6 中裏也可使用 const 語法進行聲明。使用 const 聲明的變量會被認爲是常量( constant ),意味着它們的值在被設置完成後就不能再被改變。正由於如此,全部的 const 變量都須要在聲明時進行初始化。試圖對以前用 const 聲明的常量進行賦值會拋出錯誤。code
// 有效的常量
const maxItems = 30;
// 語法錯誤:未進行初始化
const name;
// 拋出錯誤
const maxItem = 50;
複製代碼
常量聲明與 let 聲明同樣,都是塊級聲明。這意味着常量在聲明它們的語句塊外部是沒法訪問的,聲明不會被提高,而且在同一個做用域內不能重複定義。orm
使用 const 聲明對象比較特殊,const 聲明會阻止對於變量綁定與變量自身值的修改,這意味着 const 聲明並不會阻止對變量成員的修改。對象
const person = { name: "Nicholas" }; // 工做正常 person.name = "Greg"; // 拋出錯誤 person = { name: "Greg" } 複製代碼
當 JS 引擎檢視接下來的代碼塊並發現變量聲明時,它會在面對 var 的狀況下將聲明提高到函數或全局做用域的頂部,而面對 let 或 const 時會將聲明放在暫時性死區內。任何在暫時性死區內訪問變量的企圖都會致使「運行時」錯誤(runtime error)。只有執行到變量的聲明語句時,該變量纔會從暫時性死區內被移除並能夠安全使用。
for (var i = 0; i < 10; i++) { process(i); } // i 在此處仍然可被訪問 複製代碼
for (let i = 0; i < 10; i++) { process(i); } // i 在此處不可訪問,拋出錯誤 console.log(i); 複製代碼
由於 var 聲明致使了變量提高
在常規的 for 循環中,你能夠在初始化時使用 const ,但循環會在你試圖改變該變量的值時拋出錯誤。由於該語句試圖更改常量的值。所以,在循環中你只能使用 const 來聲明一個不會被更改的變量。
var funcs = []; // 在一次迭代後拋出錯誤 for (const i = 0; i < 10; i++) { funcs.push(function() { console.log(i); }); } 複製代碼
const 變量在 for-in 或 for-of 循環中使用時,與 let 變量效果相同。所以下面代碼不會致使出錯,由於循環爲每次迭代建立了一個新的變量綁定,而不是試圖去修改已綁定的變量的值。
var funcs = [], object = { a: true, b: true, c: true }; // 不會致使錯誤 for (const key in object) { funcs.push(function() { console.log(key); }); } funcs.forEach(function(func) { func(); // 依次輸出 "a"、 "b"、 "c" }); 複製代碼
在默認狀況下使用 const ,而只在你知道變量值須要被更改的狀況下才使用 let 。這在代碼中能確保基本層次的不可變性,有助於防止某些類型的錯誤。