1.let:聲明變量,有塊級作用域,不允許在同一作用域內(nèi)重復聲明,在不同作用域內(nèi)可以重復聲明,let不像var那樣會發(fā)生“變量提升”現(xiàn)象。所以,變量一定要在聲明后使用,否則報錯。只要塊級作用域內(nèi)存在let命令,它所聲明的變量就“綁定”(binding)這個區(qū)域,不再受外部的影響(稱為暫存死區(qū)),循環(huán)中的let作用域,注意瀏覽器兼容性。
2.var:聲明變量和常量,沒有塊級作用域,var聲明存在變量提升
3.const:聲明一個只讀的常量。一旦聲明,常量的值就不能改變。也可用于聲明對象,數(shù)組。
4.ES6明確規(guī)定,如果區(qū)塊中存在let和const命令,這個區(qū)塊對這些命令聲明的變量,從一開始就形成了封閉作用域。凡是在聲明之前就使用這些變量,就會報錯。
例子:
// var 的情況
console.log(foo); // 輸出undefined
var foo = 2;
// let 的情況
console.log(bar); // 報錯ReferenceError
let bar = 2;
function test(){
{
var a = 1;
}
alert(a); a可以訪問到alert出1
}
function test(){
{
let a = 1;
}
alert(a); a不能夠被訪問到alert報錯,因為let具有塊級作用域,只在let 聲明的那個作用域內(nèi)可以訪問
}
function test(){
{
let a = 1;
let a = 2; 這樣會報錯在同一作用域下不能重復聲明
}
alert(a); a不能夠被訪問到alert報錯,因為let具有塊級作用域,只在let 聲明的那個作用域內(nèi)可以訪問
}
function test(){
let a = 3;
{
let a = 1;
let a = 2; 這樣會報錯在同一作用域下不能重復聲明
}
alert(a); alert出3
}
function test(){
let a = 3; 會報錯,因為let在同一作用域下不允許重復聲明,而var沒用塊級作用域相當于在這個作用域聲明了a
{
var a = 1; var沒有塊級作用域相當于在外面聲明了一個a
}
alert(a);
}
function test(){
var a = 3; 不會報錯
{
let a = 1; 這個let聲明的a是在當前這個塊級作用下的a,不受外面作用域下a的沖突影響
}
alert(a); alert出3
}
function test(){
let a = 3; 不會報錯 因為a = 1 聲明在全局 而let a = 3聲明在function test()作用域下
{
a = 1; 沒有聲明符聲明相當于在全局聲明了一個a
}
alert(a); alert出3 就近原則 let a = 3 在函數(shù)作用域內(nèi)
}
ps:以上實例所用let聲明的a為常量所以正確應(yīng)該全部改為使用const聲明
對于復合類型的變量,變量名不指向數(shù)據(jù),而是指向數(shù)據(jù)所在的地址。const
命令只是保證變量名指向的地址不變,并不保證該地址的數(shù)據(jù)不變,所以將一個對象聲明為常量必須非常小心。
const foo = {};
foo.prop = 123;
foo.prop// 123
foo = {}; // TypeError: "foo" is read-only
上面代碼中,常量foo儲存的是一個地址,這個地址指向一個對象。不可變的只是這個地址,即不能把foo指向另一個地址,但對象本身是可變的,所以依然可以為其添加新屬性。
const a = [];
a.push('Hello'); // 可執(zhí)行
a.length = 0; // 可執(zhí)行
a = ['Dave']; // 報錯
上面代碼中,常量a是一個數(shù)組,這個數(shù)組本身是可寫的,但是如果將另一個數(shù)組賦值給a,就會報錯。
window.a = 1;
a // 1
a = 2;
window.a // 2
頂層對象,在瀏覽器環(huán)境指的是window對象,在Node指的是global對象。ES5之中,頂層對象的屬性與全局變量是等價的。上面代碼中,頂層對象的屬性賦值與全局變量的賦值,是同一件事。
ES6為了改變這一點,一方面規(guī)定,為了保持兼容性,var命令和function
命令聲明的全局變量,依舊是頂層對象的屬性;另一方面規(guī)定,let命令、const命令、class命令聲明的全局變量,不屬于頂層對象的屬性。也就是說,從ES6開始,全局變量將逐步與頂層對象的屬性脫鉤。
var a = 1;
// 如果在Node的REPL環(huán)境,可以寫成global.a
// 或者采用通用方法,寫成this.a
window.a // 1
let b = 1;
window.b // undefined
上面代碼中,全局變量a由var命令聲明,所以它是頂層對象的屬性;全局變量b由let命令聲明,所以它不是頂層對象的屬性,返回undefined。
更詳細參考阮一峰let和const