以往,在 JavaScript
中聲明變量的惟一方式是使用關鍵字 var
。爲了理解爲什麼添加了 let
和 const
,咱們先看一個示例,瞭解使用 var
會帶來怎樣的麻煩。數組
下面代碼中你認爲運行 getClothing(false)
後的輸出是什麼?瀏覽器
function getClothing(isCold) { if (isCold) { var freezing = 'Grab a jacket!'; } else { var hot = 'It's a shorts kind of day.'; console.log(freezing); } }
答案是輸出undifind
, 本質上,在執行任何 JavaScript
代碼以前,全部變量都會被「提高」,也就是提高到函數做用域的頂部。所以在運行時,getClothing()
函數實際上看起來以下所示…數據結構
function getClothing(isCold) { var freezing, hot; if (isCold) { freezing = 'Grab a jacket!'; } else { hot = 'It's a shorts kind of day.'; console.log(freezing); } }
使用 let
和 const
聲明的變量解決了這種提高問題,由於它們的做用域是到塊,而不是函數。以前,當你使用 var
時,變量要麼爲全局做用域,要麼爲本地做用域,也就是整個函數做用域。 函數
若是在代碼塊(用花括號 { }
表示)中使用 let
或 const
聲明變量,那麼該變量會陷入暫時性死區(temporal dead zone
),直到該變量的聲明被處理。這種行爲會阻止變量被訪問,除非它們被聲明瞭。this
下面例子中, 你認爲運行 getClothing(false)
後的輸出是什麼?指針
function getClothing(isCold) { if (isCold) { const freezing = 'Grab a jacket!'; } else { const hot = 'It's a shorts kind of day.'; console.log(freezing); } }
答案是 ReferenceError: freezing is not defined.
code
let 和 const 還有一些其餘有趣特性。
let
聲明的變量能夠從新賦值,可是不能在同一做用域內從新聲明。const
聲明的變量必須賦初始值,可是不能在同一做用域內從新聲明,也沒法從新賦值。let instructor = 'James'; instructor = 'Richard'; console.log(instructor); //Richard
const instructor = 'James'; instructor = 'Richard'; console.log(instructor); //SyntaxError: Identifier 'instructor' has already been declared
最大的問題是什麼時候應該使用 let
和 const
?通常法則以下:對象
let
const
。由於 const
是聲明變量最嚴格的方式,咱們建議始終使用 const
聲明變量,由於這樣代碼更容易讀懂,你知道標識符在程序的整個生命週期內都不會改變。若是你發現你須要更新變量或更改變量,則回去將其從 const
切換成 let
。生命週期
const
實際上保證的,並非變量的值不得改動,而是變量指向的那個內存地址不得改動。對於簡單類型的數據(數值、字符串、布爾值),值就保存在變量指向的那個內存地址,所以等同於常量。但對於複合類型的數據(主要是對象和數組),變量指向的內存地址,保存的只是一個指針,const
只能保證這個指針是固定的,至於它指向的數據結構是否是可變的,就徹底不能控制了。所以,將一個對象聲明爲常量必須很是當心。ip
const foo = {}; // 爲 foo 添加一個屬性,能夠成功 foo.prop = 123; foo.prop // 123 // 將 foo 指向另外一個對象,就會報錯 foo = {}; // TypeError: "foo" is read-only
上面代碼中,常量foo
儲存的是一個地址,這個地址指向一個對象。不可變的只是這個地址,即不能把foo
指向另外一個地址,但對象自己是可變的,因此依然能夠爲其添加新屬性。
頂層對象,在瀏覽器環境指的是window
對象,在 Node
指的是global
對象。ES5
之中,頂層對象的屬性與全局變量是等價的。
從 ES6 開始,全局變量將逐步與頂層對象的屬性脫鉤。
var a = 1; // 若是在 Node 的 REPL 環境,能夠寫成 global.a // 或者採用通用方法,寫成 this.a window.a // 1 let b = 1; window.b // undefined
上面代碼中,全局變量a
由var
命令聲明,因此它是頂層對象的屬性;全局變量b
由let
命令聲明,因此它不是頂層對象的屬性,返回undefined
。
還有必要使用 var
嗎?沒有了。
在某些狀況下有必要使用 var
,例如若是你想全局定義變量,可是這種作法一般都不合理,應該避免。從如今開始,建議放棄使用 var
,改成使用 let
和 const
。