區別
1.使用var聲明的變量,其作用域為該語句所在的函數內,且存在變量提升現象;
2.使用let聲明的變量,其作用域為該語句所在的代碼塊內,不存在變量提升;
3.let不允許在相同作用域內,重復聲明同一個變量。
1.基本語法
{
let a = 125;
var b = 521;
}
a // Uncaught ReferenceError: a is not defined
b // 521
上面代碼中,使用let聲明的變量報錯,var聲明的返回正確的值,這說明,let聲明的變量只在它所在的代碼塊有效。
let配合for循環的應用
for (let i = 0; i < 5; i++) {
console.log(i); //0 1 2 3 4
}
console.log(i); //ReferenceError: i is not defined
上面代碼中,計數器i只在for循壞體內有效,再循環體外引用就會報錯。
下面是常見的面試題目:
for (var i = 0; i <10; i++) {
setTimeout(function() { // 同步注冊回調函數到 異步的 宏任務隊列。
console.log(i); // 執行此代碼時,同步代碼for循環已經執行完成
}, 0);
}
// 輸出結果
//10 共10個
如果把 var改成 let聲明:
// i雖然在全局作用域聲明,但是在for循環體局部作用域中使用的時候,變量會被固定,不受外界干擾。
for (let i = 0; i < 10; i++) {
setTimeout(function() {
console.log(i); // i 是循環體內局部作用域,不受外界影響。
}, 0);
}
// 輸出結果:
0 1 2 3 4 5 6 7 8 9
另外,for循環還有一個特別之處,就是設置循環變量的那部分是一個父作用域,而循環體內部是一個單獨的子作用域。
for (let i = 0; i < 3; i++) {
let i = 'love';
console.log(i);
}
// love
// love
// love
上面代碼正確運行,輸出了 3 次abc。這表明函數內部的變量i與循環變量i不在同一個作用域,有各自單獨的作用域。
2.不存在變量提升
var命令會發生”變量提升“現象,即變量可以在聲明之前使用,值為undefined。
let命令則不同,它所聲明的變量一定要在聲明后使用,否則報錯。
// var 的情況
console.log(ar); // 輸出undefined
var ar = 512;
// let 的情況
console.log(et); // 報錯ReferenceError
let et = 512;
上面代碼變量ar用var聲明,會發生變量提升,因沒有值,所以會輸出undefined。變量et用let聲明的則不會發生變量提升。
暫時性死區
var tmp=521;
if(true){
tmp='abc';//ReferenceError: tmp is not defined
let tmp;
}
上面代碼中,存在全局變量tmp,但是塊級作用域內let又聲明了一個局部變量tmp,導致后者綁定這個塊級作用域,所以在let聲明變量前,對tmp賦值會報錯。
ES6 明確規定,如果區塊中存在let和const命令,這個區塊對這些命令聲明的變量,從一開始就形成了封閉作用域。凡是在聲明之前就使用這些變量,就會報錯。(使用const聲明的是常量,在后面出現的代碼中不能再修改該常量的值。)
總之,在代碼塊內,使用let命令聲明變量之前,該變量都是不可用的。這在語法上,稱為“暫時性死區”(temporal dead zone,簡稱 TDZ)。
不允許重復聲明
let不允許在相同作用域內,重復聲明同一個變量。
// 報錯
function func() {
let a = 10;
var a = 1;
}
// 報錯
function func() {
let a = 10;
let a = 1;
}
因此,不能在函數內部重新聲明參數。
function func(arg) {
let arg; // 報錯
}
function func(arg) {
{
let arg; // 不報錯
}
}