不存在變量提升
按照程序語法邏輯,變量應(yīng)該在聲明語句之后才可以使用,即變量可以在聲明之前使用,其值為undefined。即所謂的“變量提升”。
```javascript
// var 的情況
console.log(foo); // 輸出undefined
var foo = 2;
為了糾正這種反人類的現(xiàn)象,ES6let所聲明的變量一定要在聲明語句之后才可以使用。
// let 的情況
console.log(bar); // 報錯ReferenceError
let bar = 2;
不允許重復(fù)聲明
在ES5中 使用var 可以對變量進行多次聲明,在ES6中let不允許在相同作用域內(nèi),重復(fù)聲明同一個變量。
let a = 1;
let a = 2;
var b = 3;
var b = 4;
a // Identifier 'a' has already been declared
b // 4
不能在函數(shù)內(nèi)部重新聲明參數(shù)。
function func(arg) {
let arg;
}
func() // 報錯
function func(arg) {
{
let arg;
}
}
func() // 不報錯
塊級作用域
ES5作用域的缺陷
ES5 只有全局作用域和函數(shù)作用域,沒有塊級作用域,這帶來很多不合理的場景。
第一種場景,內(nèi)層變量可能會覆蓋外層變量。
var tmp = new Date();
function f() {
console.log(tmp);
if (false) {
var tmp = 'hello world';
}
}
f(); // undefined
上面代碼的原意是,if代碼塊的外部使用外層的tmp變量,內(nèi)部使用內(nèi)層的tmp變量。但是,函數(shù)f執(zhí)行后,輸出結(jié)果為undefined,原因在于變量提升,導(dǎo)致內(nèi)層的tmp變量覆蓋了外層的tmp變量。
第二種場景,用來計數(shù)的循環(huán)變量泄露為全局變量。
var s = 'hello';
for (var i = 0; i < s.length; i++) {
console.log(s[i]);
}
console.log(i); // 5
上面代碼中,變量i只用來控制循環(huán),但是循環(huán)結(jié)束后,它并沒有消失,搖身一變成為了全局變量。
ES6 的塊級作用域
let實際上為 JavaScript 新增了塊級作用域。let所聲明的變量,只在let命令所在的代碼塊內(nèi)有效。
{
let a = 10;
var b = 1;
}
a // ReferenceError: a is not defined.
b // 1
分別用let和var聲明了兩個變量。然后在代碼塊之外調(diào)用這兩個變量,結(jié)果let聲明的變量報錯,var聲明的變量返回了正確的值。這表明,let聲明的變量只在它所在的代碼塊有效。
for循環(huán)的計數(shù)器,非常適合使用let命令。
for (let i = 0; i < 10; i++) {
// ...
}
console.log(i);
// ReferenceError: i is not defined
上面代碼中,計數(shù)器i只在for循環(huán)體內(nèi)有效,在循環(huán)體外引用就會報錯。
下面的代碼如果使用var,最后輸出的是10。
var a = [];
for (var i = 0; i < 10; i++) {
a[i] = function () {
console.log(i);
};
}
a[6](); // 10
上面代碼中,變量i是var命令聲明的,在全局范圍內(nèi)都有效,所以全局只有一個變量i。每一次循環(huán),變量i的值都會發(fā)生改變,而循環(huán)內(nèi)被賦給數(shù)組a的函數(shù)內(nèi)部的console.log(i),里面的i指向的就是全局的i。也就是說,所有數(shù)組a的成員里面的i,指向的都是同一個i,導(dǎo)致運行時輸出的是最后一輪的i的值,也就是 10。
如果使用let,聲明的變量僅在塊級作用域內(nèi)有效,最后輸出的是 6。
var a = [];
for (let i = 0; i < 10; i++) {
a[i] = function () {
console.log(i);
};
}
a[6](); // 6