ES6之前的JavaScript變量由var聲明,而var聲明的變量是始終保存在內存中的,爲了實現塊級作用域,我們會使用閉包模擬,但實際上非常的不方便。ES6添加了let和const標識符,彌補了這些不足。
var和閉包
我們先來了解一下var和閉包,下面用花括號生成一個塊級作用域,在其內創建變量count:
{
var count = 5;
}
console.log(count);//5
我們可以看到在塊級作用域外部仍然可以訪問count變量。實際上這段代碼等效爲:
var count;
{
count = 5;
}
console.log(count);//5
這就是說,變量count的聲明被提升至函數頂部,而初始化操作仍舊留在原初執行。
如果想要模擬塊級作用域,實際上我們要做的是在使用變量的時候爲其賦值塊級作用域的值。利用函數的特性(可以參考這裏理解),再來看一下閉包:
(function(){
var count = 5;
console.log(count);//5
})();
console.log(count);//報錯,count未定義
之所以如此,是因爲函數過程是動態執行的,因此在函數內的變量是動態創建的。
let和const
ES6之後就不需要這麼麻煩了,可以看下面這個例子:
{
let count = 5;
console.log(count);//5
}
console.log(count);//報錯
總結一下,let和const聲明的變量都是塊級作用域,在塊級作用域之外訪問就會報錯。
此外,他們還有另一個特性,那就是不允許重定義,像下面這樣就會報錯:
var value = 30;
let value = 2;//報錯,不能重複定義
const與let的區別在於:const必須初始化且只能初始化一次,若改變變量值就會報錯。此外,const變量如果是對象,對象的屬性可以修改。
另外我們需要注意一個特性,看下面的例子:
if(condition){
console.log(typeof value);//引用錯誤
let value = "blue";
}
但是這樣寫就不會報錯:
console.log(typeof value);//"undeined"
if(condition){
let value = "blue";
}
循環中的塊作用域綁定
看下面的例子:
for(var i=0;i<10;i++){
console.log(i);//0...9
}
console.log(i);//10
for(let i=0;i<10;i++){
console.log(i);//0...9
}
console.log(i);//報錯
for(const i=0;i<10;i++){
console.log(i);//輸出0後報錯,因爲const不能改變
}
console.log(i);//報錯
但是const可以用在for-in或for-of中,不會報錯,如下。
var obj = {a:true,b:true,c:true}
for(const key in obj){
console.log(key);//a/b/c
}
全局塊作用域綁定
當var被用於全局作用域時,它會創建一個新的全局變量作爲全局對象(瀏覽器環境中的window對象)的屬性。這樣就有可能會出現下面的錯誤。
//在瀏覽器中
var RegExp = "Hello!";
console.log(window.RegExp );//"Hello!"
但使用let就不會出現這種錯誤。
//在瀏覽器中
let RegExp = "Hello!";
console.log(RegExp );//"Hello!"
console.log(window.RegExp === RegExp);//false
最後建議:默認使用const,只有確實需要修改變量時使用let。