let,const和var
在之前的js版本中,声明变量一直都是用var, 这个估计大家都很熟悉了,那么它的作用呢就是用来声明一个变量,比如像这样子:var a = 10;在这里我们就用var声明了一个变量a,并且在声明的同时给这个变量a赋值了,也就是10;那么这时候如果我们去引用这个变量,那么得到的结果就是10,这没什么稀奇的,在这里就不再赘述了。
那么在es6里面新增了两个声明变量的方法,一个是let,用于声明变量。一个是const,用于声明常量。我们来看一下这三者之间的区别
let和var的区别
这两个关键字都是用于声明变量的,在这种情况(先声明后使用)下使用let和var的时候其实是没有区别的。
var a = 10
let b = 20
console.log(a,b) //10 20
区别一:变量提升
用var声明的变量会被提升,而用let声明的变量不会被提升 (变量提升后面具体讲)
区别二:重复声明
用var可以重复声明同一个变量,而let不可以 我们知道,用var声明一个变量之后,其实还可以再次用var去声明这个变量,不过是后者覆盖前者,并没有太大意义。不过至少不会报错,而如果用let去声明变量的话,就得稍微注意一点,因为let不可以在同一个作用域下重复声明同一个变量:
var a = 10
var a = 20
let b = 10
let b = 20 //Uncaught SyntaxError: Identifier 'b' has already been declared
如果用let重复声明同一个变量,那么这时候就会报错:变量b已经被声明了。
区别三:块级作用域
用let声明的变量支持块级作用域
es6新提出来了一个块级作用域的概念,在之前,作用域只存在函数里面,或者全局。而es6提出的块级作用域则是一个大括号{}就是一个块级作用域,也就是说if语句里面都存在作用域概念了,比如:
if(true){
var a = 12;
}
console.log(a);// 12
if(true){
let b = 123;
}
console.log(b);// error : b is not defined
const的特性
和let一样,const也是es6新增的关键字,let用于声明变量,而const用于声明常量。当然,const和let也有一些相同点:
- const 不会变量提升,准确来说应该是常量提升,也就是说不会被提前与解析
- const 不能重复声明同一个常量
- const 支持块级作用域
然后我们再来说一下这两个家伙的不同点:
区别一:const声明的常量不能被修改
正常来说,我们不管是用var声明的变量,还是用let声明的变量,后期都是可以对这个变量再次赋值的,也就是说可以修改。而常量一旦定义了,后期就不能修改了。如:
const a = 1
a = 3 //VM1065:2 Uncaught TypeError: Assignment to constant variable.
一旦你尝试着去修改一个常量的时候,浏览器就会告诉你,常量不可以被修改! 不过有一个方法是可以做到修改常量的,就是声明常量的时候,给常量赋值一个对象,然后后期再去修改这个对象里面的值就可以了,不过这么做没有任何的意义,常量存在的意义就在于其不可更改性。所以这个方法也就不再多说了
区别二:常量在声明的时候,必须赋值
其实这一点特别好理解,常量在后期没有办法再次进行赋值,所以只能在声明的时候进行赋值
另外有一点要特别关注一下,比如:
var abc= 123;
if (true) {
abc= 'rstyjstyjd'; // referenceError
let abc;
}
在上面的代码中,存在全局变量abc, 但是块级作用域内let又声明了一个变量abc, 导致后者绑定这个块级作用域,所以在let变量声明之前,对abc的赋值会报错。 ES6中明确规定,如果区块中存在let和const命令,这个区块对这些命令声明的变量,从一开始就形成了封闭作用域,凡是在声明之前就使用这些变量就会报错。
那为什么还要用const
- 不会一不小心给一个不应当被修改的变量或者函数赋值
- 别人读起代码来会也能认知到某个变量是不会被修改的
三个例子弄懂变量提升
1、程序的运行结果为:100 10 100
var a = 10;
function test(){
a = 100;
console.log(a);
console.log(this.a);
var a;
console.log(a);
}
test();
解析:Javascript在执行前会对整个脚本文件的声明部分做完整分析(包括局部变量),从而确定变量的作用域,所以在函数test执行前,由于第6行声明了局部变量a,所以函数内部的a都指向已经声明的局部变量,所以第4行输出100。第5行输出this.a,我们都知道,函数内部的this指向的是函数的调用者,在这里函数test被全局对象调用,所以this指针指向全局对象(这里即window),所以this.a = window.a,一开始声明了全局变量a=10,所以第5行输出结果为10。第7行输出结果为100,因为局部变量a在第3行已经被赋值了100,所以直接输出局部变量a的值。
2、程序的运行结果为:undefined 10
var a = 100;
function test(){
console.log(a);
var a = 10;
console.log(a);
}
test();
解析:看了第1个例子,可能有同学会认为输出结果是10 10,但是结果却不是10 10,为什么呢?仔细看第1个例子解析的第一句话,Javascript在执行前会对整个脚本文件的声明部分做完整分析(包括局部变量),但是不能对变量定义做提前解析,在这个函数中,执行第3行前,可以认为已经声明了变量a,但是并没有定义(这里即赋值),所以第3行输出结果为undefined,执行第4行a =10后,变量a的值就为10,所以第5行输出结果为10。
3、程序的运行结果为:100 10 10
var a = 100;
function test(){
console.log(a);
a = 10;
console.log(a);
}
test();
console.log(a);
解析:我们知道在函数内部,一般用var声明的为局部变量,没用var声明的一般为全局变量,在test函数内,a=10声明了一个全局变量,所以第3行的a应该输出全局变量的值,而在函数执行之前已经声明过一个全局变量并赋值100,所以这里第上输出100。第4行给全局变量a 重新赋值10,所以全局变量a的值变成10,所以第5行输出10。而在函数test外部,第8行输出全局变量a的值,因为全局变量被重新赋值为10,所以输出结果即为10。