let所在的代码块有效
var有变量提升
作用域与全局变量
var a = [];
for(let i = 0;i<5;i++){
a[i] = function(){
console.log(i);
}
}
a[3]();//3
var a = [];
for(var i = 0;i<5;i++){
a[i] = function(){
console.log(i);
}
}
a[3]();//5
这是为什么,因为let仅在所在作用域有效,即每次循环中,所以每个循环都创建了一个新的变量i,给其赋值。
而var声明后在全局有效,此时i在5次循环后自加变成了5,所以输出的是5。
另外:
通过let的特性,我们还可以发现for的一个性质:
for(let i = 0;i<3;i++){
let i = "a";
console.log(i);
}
//a
//a
//a
不难发现两个i所处的作用域不同,for循环所在的作用域是父作用域,而每个循环体内的是子作用域。此时读取变量是从当前作用域着手,寻找不到后再寻求更高一级的作用域。
变量提升
console.log(a);//undefined
var a = 1;
console.log(b);//报错ReferenceError
let b = 1;
var在声明前即可使用,这就是变量提升,因为声明前未赋值,所以输出为undefined。let则直接报错。
暂时性死区
倘若上级作用域有出现同名变量,let会将所在作用域的同名变量锁住,在该变量未声明前所有对同名变量的操作都会报错。
var tmp = 123;
if (true) {
tmp = 'abc'; // ReferenceError
let tmp;
}
总之,在代码块内,使用let命令声明变量之前,该变量都是不可用的。这在语法上,称为“暂时性死区”(temporal dead zone,简称 TDZ)。
注意:此时typeof也会报错了
不允许重复声明
let不能在同一作用域重复声明一个变量,否则会报错。
// 报错
function func() {
let a = 10;
var a = 1;
}
// 报错
function func() {
let a = 10;
let a = 1;
}
函数内不能重复声明变量,案例如下:
function func(arg) {
let arg;
}
func() // 报错
function func(arg) {
{
let arg;
}
}
func() // 不报错