ES6之let与const
JavaScript共包含三个部分:ECMAScript、DOM和BOM,而我们今天开始所要讲的ES6的全称就是ECMAScript6,它是2015年发布的ECMAScript标准,故又被称之为ECMAScript2015。而后每年都会更新一个新版本,并以该年份置于其后作为标识,而这些从2015年开始的ECMAScript版本都被统称为ES6。
ES6相对之前版本增加了很多新的特性,但是也有很多都只是语法糖,也就是说实现功能和之前一样,只是语法更简洁了而已(如箭头函数、类)。这些新特性新语法给我们开发带来了很多便利,提高了工作效率和降低了维护成本。遗憾的是,现代浏览器对ES6兼容参差不齐,所以导致很多人虽然想用但是不敢用。不过幸亏有了像Babel这样优秀的编译工具,能将ES6语法编译成现代浏览器能识别的ES6之前版本,这样我们又可以轻松愉快地使用它了。
接下来,就让我来为大家一步步地打开这扇通往ES6的大门吧!
一、let——变量声明
在ES6之前,我们是使用var
来声明变量,那么我们就来简单说说var
和let
之间到底有什么区别。
1. 块级作用域
①var
声明的变量不是块级作用域,所以代码块之外能访问代码块中的变量。
{ // 代码块
var a = 0; // 全局变量,外部可访问
}
console.log(a); // 0
②let
声明的变量是块级作用域,所以代码块之外无法访问代码块中的变量。
{ // 代码块
let a = 0; // 局部变量,外部可访问
}
console.log(a); // 报错
2. 暂时性死区
①var
声明的变量会进行变量提升,也就是说,该变量声明总会被提升到作用域最顶部。
{
a = 0;
var a;
}
console.log(a); // 0
变量a
的作用域为全局,故以上代码其实相当于下面代码:
var a; // 变量提升
{
a = 0;
}
console.log(a); // 0
然后再看下面这个例子:
console.log(a); // undefined
{
a = 0;
var a;
}
你会发现即使最上面没有声明过变量a
,我们去打印它也并不会报错,这是因为var a;
会提升到console.log(a);
之前。
②let
比较霸道,用它声明的变量必须在其作用域内并在声明之后使用,即使全局已经用var
声明过该变量也不行。
{
a = 0; // 在声明前赋值会报错
let a;
}
// 在声明前使用就会报错,不管代码块外面是否声明过这个变量
var a;
{
a = 0; // 报错
let a;
}
后面这个例子可以看到,虽然全局已经声明过了变量a
,本来代码块中是可以正常访问到这个变量的,但因为这个代码块中用let
又声明了一次变量a
,因此这个代码块就像一片“死区”一样,无法访问外部变量,当然这只是针对这个用let
声明的a
来说是“死区”,若是用var
声明的其他变量则照样可以访问外部变量。这种用let
绑定整个代码块的“霸道行为”,在语法上被称之为“暂时性死区”。
其实,按照我个人理解,我们完全可以不用去理会这个“暂时性死区”的具体含义,只需知道的是,不管什么情况,let
声明的变量,必须在其声明之后才能使用。
3. 不能重复声明
① var
比较开放,同一作用域内,同一变量可以声明多次,并不会报错。
var a = 0;
var a = 1;
console.log(a); // 1
以上代码相当于:
var a;
a = 0;
a = 1;
console.log(a); // 1
② let
比较专一,同一作用域内,同一变量只能声明一次,否则就会报错。
let a = 0;
let a = 1; // 报错
let a = 0;
var a = 1; // 变量提升,报错
var a = 1;
let a = 0; // 报错
let a = 0;
{
var a = 1; // 变量提升,报错
}
但是注意以下情况是正常的:
let a = 0;
{
let a = 1; // 无变量提升,是局部变量,与全局声明的变量不在同一个作用域
}
console.log(a); // 0
var a = 0;
{
let a = 1; // 无变量提升,是局部变量,与全局声明的变量不在同一个作用域
}
console.log(a); // 0
其实只需记住一点:在同一作用域中判断,这样就能很好地判断是否重复声明了。
二、const——常量声明
const
与let
很像,所以本文也是直接把他们放在一起说,它几乎与let
一样,只不过它声明的是常量,常量值不能更改,且必须在声明时赋值。
1. 声明常量
既然是常量,当然是不可更改的。
const a = 0;
a = 1; // 报错,常量值不可更改
但是要注意下面这种情况是可以的:
const a = [];
a.push(1);
console.log(a) // [1]
这是为什么呢?不是说常量值不可更改吗?可现在为什么又把空数组变成了[1]
呢?
其实道理很简单,我们开始赋值给常量a
的只是数组的引用而已(就是数组的存储地址),当我们去修改该数组时,这个引用并不会发生改变。这就像是你给家里房子装修布置了一下,但是家庭地址并没有变,可是如果你直接换了一套新房,那可就不一样了。
const a = [];
a = [1]; // 报错,引用不可更改
这是重新赋值了新的数组,引用发生改变,所以就会报错。
2. 具有let相同特性
块级作用域、先声明后使用和不能重复声明这些特性对于const
一样适用,因此不再赘述。
但需要注意的是,用var
或let
声明过的变量,再声明相同名称常量也算是重复声明。
var a;
const a = 0; // 报错
let a;
const a = 0; // 报错
const a = 0;
var a; // 报错
const a = 0;
let a; // 报错
3. 声明时必须赋值
const a; // 报错
let
声明的是变量,所以可以先声明后赋值,可const
不一样,它声明的时常量,你在声明的同时就必须给其赋值,否则它不会给你好心地默认给你赋个undefined
,而是毫不留情地给你报错!
重点总结
①
let
在代码块中声明的变量为局部变量
②let
声明的变量,必须在其声明之后才能使用
③let
在同一作用域内不可重复声明同一变量,包括var
或const
声明过的也不行
④const
声明常量,不可更改,但如果是引用类型常量,则可以修改其内部数据
⑤const
具有let
相同特性(包括①②③所有特性)
⑥const
在声明常量时必须同时进行赋值