var、let、const声明变量的区别
之前提到了var声明带来的一些不好的地方,ES6的let和const能方便的解决。
一、let声明
引入let不仅仅是解决变量声明的问题,还引入了块级作用域的概念,即代码运行遇到花括号自动创建块级作用域,执行过花括号后销毁块级作用域。
解决的变量声明问题:
1.全局变量挂载到全局对象问题
let声明的变量不会挂载到全局对象上,也就是说上一篇所说的
var alert = 'a';
window.alert('这是弹窗')//这一句报错
这种情况,在使用let声明之后
let alert = 'a';
window.alert('这是弹窗');//出现弹窗
alert就是一个值为’a’的字符串,不影响window下面的alert函数,说明let声明的全局变量不回挂载到window下。
2.允许重复声明覆盖的问题
上一篇说到,如果我们在前面几行就声明了一个变量a,隔了好多好多行后忘记了声明过a又声明了一个a,就会覆盖掉第一个a,导致许多意料之外的错误。
如果用let就不允许同作用域重复声明变量
let a =1;
let a = 2;//报错
在块级作用域中声明的变量不会被作用域外访问
{
let a = 1;
}
console.log(a)//访问不到
3.变量提升,怪异地访问、闭包
上一篇举的例子是
var div = document.getElementsByTagName("div");
for (var i = 0; i < 10; i++) {
div[i].onclick = function() {
console.log(i); //输出都是10
}
}
由于变量i提升了,导致的闭包问题,以前我们的做法是使用立即执行函数包裹,但是有了let之后,我们只需要用let声明,其他不变就行,
for (let i = 0; i < 10; i++) {
在循环中用let声明的循环变量,不是全局变量,每一次循环都会在块级作用域中声明一个i2,然后把循环变量的值赋值给这个i2,循环所使用的就是这个i2。来看代码
var div = document.getElementsByTagName("div");
for (let i = 0; i < 10; i++) {
//相当于每次循环都在这
//let i2 = i;
div[i].onclick = function() {
console.log(i); //相当于console.log(i2)
}
}
同时,let声明的循环变量在循环结束后会销毁,也就是说全局访问不到 i。
不过let也不是说完全没有变量提升,其实底层里let声明的变量还是会提升,但是同时放入临时性死区,只有在声明之后的才会从临时性死区中取出变量,在此之前会报错未声明,因此可以看成let声明的变量不会提升。
二、const声明
const声明与let几乎一样,除了以下几点之外,用法相同,也能解决上面的问题。
1.const声明的是常量,不可变
也就是说const声明的变量一旦声明就不能再更改了,因此也就要求const声明时同时赋值。需要注意的是这里说的不可变指的是内存空间不可变,内存空间中的存放地址所指向的空间依然能变
const a = 1;//这个a打此之后不能再变成其他的,永远是1
const b = {
name:'b'
}//b.name是可以被修改为其他的值的
2.一些特殊的、一定不会变的值用常量表示
圆周率、月地距离等等通常用常量表示,而常量全部使用大写字母,如PI,如果有多个词用下划线隔开NODE_ENV.
3.for循环中循环变量不可用const常量
正是因为const不可改,但是for循环每次都改,所以不能在声明循环变量时使用const声明的常量。