一、let命令
基本用法
es6中let的命令,用来声明变量,用法与var类似,但是声明的变量,只能在let所在的代码块中有效。形成了局部作用域,对比es5中只有函数作用域和全局作用域,es6中多了局部作用域。
{
let a = 1;
console.log(a);//1
}
console.log(a);//a is not defined
for循环中使用let与使用var的区别。
//使用var 来声明变量
var a = [];
for (var i = 0; i < 10; i++) {
a[i] = function () {
console.log(i);
};
}
a[6](); // 10
//使用let来声明变量
var a = [];
for (let i = 0; i < 10; i++) {
a[i] = function () {
console.log(i);
};
}
a[6](); // 6
原因:for循环有一个特别之处,设置循环的变量的部分是父作用域 ,而循环体内容是一个单独的作用域,每循环一次生产一个新的子作用域。下面代码正确运行,输出了 3 次2
。这表明函数内部的变量i
与循环变量i
不在同一个作用域,有各自单独的作用域(同一个作用域不可使用 let
重复声明同一个变量)。
for (let i = 0; i < 3; i++) {
let i = '2';
console.log(i);
}
// 2
// 2
// 2
不存在变量提升
var
命令会发生“变量提升”现象,即变量可以在声明之前使用,值为undefined
。这种现象多多少少是有些奇怪的,按照一般的逻辑,变量应该在声明语句之后才可以使用。为了纠正这种现象,let
命令改变了语法行为,它所声明的变量一定要在声明后使用,否则报错。
// var 的情况
console.log(foo); // 输出undefined
var foo = 2;
// let 的情况
console.log(bar); // 报错ReferenceError
let bar = 2;
暂时性死区
只要在块作用域中存在let命令声明变量,这个变量所在声明就被绑定,在声明之前使用变量就会报错(ReferenceError)
if (true) {
// TDZ开始
tmp = 'abc'; // ReferenceError
console.log(tmp); // ReferenceError
let tmp; // TDZ结束
console.log(tmp); // undefined
tmp = 123;
console.log(tmp); // 123
}
ES6 明确规定,如果区块中存在let
和const
命令,这个区块对这些命令声明的变量,从一开始就形成了封闭作用域。凡是在声明之前就使用这些变量,就会报错。
总之,在代码块内,使用let
命令声明变量之前,该变量都是不可用的。这在语法上,称为“暂时性死区”(temporal dead zone,简称 TDZ)。
不能重复声明
let
不允许在相同作用域内,重复声明同一个变量。
// 报错
function func() {
let a = 10;
var a = 1;
}
// 报错
function func() {
let a = 10;
let a = 1;
}
二、const命令
const基本性质与let相同。
不同点:
const声明的时候就要赋值,const赋值的不可修改。
本质:const
实际上保证的,并不是变量的值不得改动,而是变量指向的那个内存地址所保存的数据不得改动。对于简单类型的数据(数值、字符串、布尔值),值就保存在变量指向的那个内存地址,因此等同于常量。但对于复合类型的数据(主要是对象和数组),变量指向的内存地址,保存的只是一个指向实际数据的指针,const
只能保证这个指针是固定的(即总是指向另一个固定的地址),至于它指向的数据结构是不是可变的,就完全不能控制了。因此,将一个对象声明为常量必须非常小心。