ES6 的一個重要特性就是有了塊的概念,引入了let、const聲明變量,在剛開始接觸這兩個標識符的時候,就當作var來用的,可是他們之間實際上是有不少差異的。本篇整理了一下,簡單的地方只是列了一個提綱,文末還有他們之間的區別,當用到的時候能夠回來看。node
js中對於未聲明的變量會報語法錯誤,對於未初始化值的變量會報undefined。編程
做用域:函數做用域、全局做用域瀏覽器
變量提高:變量的==聲明位置==提高到當前做用域頂部,可是變量的==初始化位置==不變。安全
塊級聲明 ----->塊級標識符----->let、constbash
----->塊級做用域(亦稱詞法做用域):指函數內部、{}之間的區域函數
塊級變量只在代碼塊內有效,代碼塊外當即銷燬。ui
要求聲明時必須進行初始化,且值一旦被設定後不可更改。spa
可是對於js對象而言, const聲明不容許修改綁定,可是容許修改綁定的值設計
ES6 明確規定,若是區塊中存在let和const命令,這個區塊對這些命令聲明的變量,從一開始就造成了封閉做用域。凡是在聲明以前就使用這些變量,就會報錯。code
總之,在代碼塊內,使用let命令聲明變量以前,該變量都是不可用的。這在語法上,稱爲「暫時性死區」(temporal dead zone,簡稱 TDZ)。
臨時死區內,使用該變量,如:typeof,都會報語法錯誤; 若是沒有造成臨時死區,使用該變量,typeof,則不會報錯。 例:2.4.二、2.4.3
2.4.1
var tmp = 123;
if (true) {
tmp = 'abc'; // ReferenceError
let tmp;
}
複製代碼
2.4.2
typeof x; // ReferenceError
let x;
複製代碼
上面代碼中,變量x使用let命令聲明,因此在聲明以前,都屬於x的「死區」,只要用到該變量就會報錯。所以,typeof運行時就會拋出一個ReferenceError。
做爲比較,若是一個變量根本沒有被聲明,使用typeof反而不會報錯。
2.4.3
typeof undeclared_variable // "undefined"
複製代碼
上面代碼中,undeclared_variable是一個不存在的變量名,結果返回「undefined」。因此,在沒有let以前,typeof運算符是百分之百安全的,永遠不會報錯。如今這一點不成立了。這樣的設計是爲了讓你們養成良好的編程習慣,變量必定要在聲明以後使用,不然就報錯。
有些「死區」比較隱蔽,不太容易發現。
function bar(x = y, y = 2) {
return [x, y];
}
bar(); // 報錯
複製代碼
上面代碼中,調用bar函數之因此報錯(某些實現可能不報錯),是由於參數x默認值等於另外一個參數y,而此時y尚未聲明,屬於「死區」。若是y的默認值是x,就不會報錯,由於此時x已經聲明瞭。
function bar(x = 2, y = x) {
return [x, y];
}
bar(); // [2, 2]
複製代碼
另外,下面的代碼也會報錯,與var的行爲不一樣。
// 不報錯
var x = x;
複製代碼
// 報錯
let x = x;
// ReferenceError: x is not defined
複製代碼
上面代碼報錯,也是由於暫時性死區。使用let聲明變量時,只要變量在尚未聲明完成前使用,就會報錯。上面這行就屬於這個狀況,在變量x的聲明語句尚未執行完成前,就去取x的值,致使報錯」x 未定義「。
var:for與 for in、 for of let:for與 for in、 for of const:for與 for in、 for of
默認使用const,只在確實須要改變變量的值時才使用let。
一、變量提高:var聲明的變量會變量提高,而塊級標識符不會。
二、變量重命名:var容許同一個做用域下變量重名,可是會覆蓋,而塊級標識符不容許在同一個做用域下變量重名。
三、全局做用域綁定: var聲明的變量,若是和全局對象相同,則仍然是覆蓋原則。 而塊級標識符和全局對象沒有任何關係。
全局對象:瀏覽器環境中是window,node環境中是global。
var a = 2;
var a = 3; // a=3
複製代碼