ES6 新增了let命令,用来声明变量。但是所声明的变量,只在let命令所在的代码块内有效。
{
let a = 5;
var b = 1;
}
alert(a) // ReferenceError: a is not defined.
alert(b) // 1
在代码块之外调用这两个变量,结果let声明的变量报错,var声明的变量返回了正确的值。所以let声明的变量只在它所在的代码块有效。
例子:
for (let i = 0; i < 100; i++) {
// ...
}
console.log(i);//ReferenceError: i is not defined
Tips: 上面代码中,计数器i只在for循环体内有效,在循环体外引用就会报错。
var a = [];
for( var i = 0; i < 100; i++){
a[i] = function () {
console.log(i);
};
}
a[12](); // 100
Tips: 变量 i 是var命令声明的,在全局范围内都有效。每一次循环,变量i的值都会发生改变,而循环内被赋给数组a的函数内部的console.log(i),里面的i指向的就是全局的i。所有数组a的成员里面的i,指向的都是同一个i,导致运行时输出的是最后一轮的i的值,也就是100。
如果使用let,声明的变量仅在块级作用域内有效,最后输出的是12。
var a = [];
for( var i = 0; i < 100; i++){
a[i] = function () {
console.log(i);
};
}
a[12](); // 12
Tips: 上面代码中,变量i是let声明的,当前的i只在本轮循环有效,所以最后输出的是12
for循环中置循环变量的那部分是一个父作用域,而循环体内部是一个单独的子作用域。
例子:
for(let i = 0; i < 4; i ++){
let i = 'aaa';
console.log(i);
}
//aaa
//aaa
//aaa
//aaa
var命令会发生”变量提升“现象,即变量可以在声明之前使用,值为undefined。而let命令所声明的变量一定要在声明后使用,否则报错。
例子:
console.log(a); // 输出undefined
var a = 5;
console.log(bar); // 报错ReferenceError
let b= 2;
暂时性死区
只要块级作用域内存在let命令,它所声明的变量就“绑定”(binding)这个区域,不再受外部的影响。
例子:
var item = 'abc'
if(true){
item = 'def'; //ReferenceError
let item;
}
Tips: 上面代码中,存在全局变量item ,但块级作用域内let又声明了一个局部变量item,后者绑定这个块级作用域,所以在let声明变量前,对tmp赋值会报错。
ES6明确规定,如果区块中存在let和const命令,这个区块对这些命令声明的变量,从一开始就形成了封闭作用域。凡是在声明之前就使用这些变量,就会报错。
let不允许在相同作用域内,重复声明同一个变量。
例子:
//报错
function(){
let a = 1;
let a = 1;
}
function(arg){
let arg; //报错
}