一句话,let和const是var的改良版,能用const就不用let, 能用let就不用var。 一、var的缺陷,先来看看使用var定义变量会有哪些问题:
- var不是块级作用域,下面的代码循环已经结束了,却还可以访问到变量test,可能会引起bug
for(var i=0;i<10;i++){
var test = i;
}
console.log(test);//9
console.log(i)//10 用来记数的变量也可以访问, 无意中就污染了全局变
- var定义的变量,有变量提升,变量提升,会对程序的维护带来困扰。
if(true){
console.log('执行了');
}else{
console.log('没执行');
var j = 2;
}
console.log(j); //输出undefined 定义变量j的代码虽然没有执行,但是却依然不会报错
- var定义的变量,不会为异步任务单独绑定变量,下面这段代码,本意是让它每隔一段时间输出0-9,结果却输出了10个10
for (var i = 0; i < 3; i++) {
setTimeout(function () {
console.log(i)
}, 1000);
- var定义的变量,可以重复定义,这样就显得非常的随意松散
var a =1;
var a =2;
console.log(a);//输出后面定义的
二、let和const就是ES6针对以上问题提出的解决方案,let和var的区别具体如下:
- let声明的变量是块级作用域的,这个特性解决了原来使用var容易污染全局变量的弊端。
for(let i=0;i<10;i++){
let test = i;
}
console.log(i);//Uncaught ReferenceError: i is not defined
console.log(test)//Uncaught ReferenceError: test is not define
- let声明的变量不存在变量提升,从let的块级作用域开始,到初始化位置,称作“暂存死区”,对于变量的暂存死区中使用变量会报Reference错误。这个特性就使得我们先定义变量再使用的变量,避免了var变量提升带来的难以查找的bug,也增强了代码的可读性。(也有文章认为let和const是有变量提升的,但是从结果上我们直接把let和const理解成没有变量提升是正确的。)
//使用var
console.log(i); // 输出undefined
var i = 2;
//使用let
console.log(j);
let j =10; //Uncaught ReferenceError: Cannot access 'j' before initializatio
- var可以重复定义变量,而let不可以,使得定义变量不再像var那么随意
//使用var
var a = 1;
var a = 2;
console.log(a); // var可以重复定义,输出2
//使用let
let i =1;
let i =2;
console.log(i);// let不能重复定义, Uncaught SyntaxError: Identifier 'i' has already been declare
- var定义的全局变量属于顶层对象,而let、const声明的全局变量属于顶层对象,这也很容易理解, 因为let的设计初衷就是块级作用域变量,不污染全局变量,显得自由灵活安全。以浏览器为例:
var a = 0;
console.log(window.a) // 0
let b = 1;
console.log(window.b) // undefine
三、以上let具有的特性,const都有,const和let的区别如下:
- const在声明常量的时候, 一定要初始化一个值:
const a=1; //正确
const b = 1;
b = 5; //TypeError: Assignment to constant variable.
const c; //SyntaxError: Missing initializer in const declaratio
- const定义的常量值不允许修改,
const a = 0;
a = 1; // TypeError: Assignment to constant variab
但是如果常量的类型为复杂类型(对象、数组等)时,对于常量值本身的操作是可以的, 因为const命令只是保证变量名指向的地址不变,并不保证该地址的数据不变。
const a = {};
a.name='小明'
console.log(a);
a = {name:'小明'};
console.log(a)
四、总结
- let和const声明的变量时块级作用域,避免了无意中全局变量污染,更加的灵活安全。另一个好处就是在循环语句中,let关键字为每次循环绑定单独绑定一个变量。
- let和const没有变量提升,提高了代码的可维护性。
- let和const不可以重复定义变量,修复var可以重复定义变量,使得变量的定义不再随意任性。
- let和const定义的变量不属于顶层对象。目的也是为了让变量定义更加自由灵活安全。
- const声明一个常量的时候,一定要赋值。
- const声明的常量并非真正意义上的常量,只保证变量名指向的地址不变,并不保证该地址的数据不变。
五、拓展
- 对于以下代码,改如何改正
//本意是要输出0-9,这段代码却输出10个10
for (var i = 0; i < 10; i++) {
setTimeout(function () {
console.log(i)
}, 1000);
解析:在js中先执行同步任务,再执行异步任务,setTimeout里面的代码是异步任务,等到执行时,var声明的变量i已经是10了。解法1,利用setTimeout函数的第三个参数把i单独绑定
for (var i = 0; i < 10; i++) {
setTimeout(function (i) {
console.log(i)
}, 1000, i);
解法2,利用闭包强制让setTimeout记住变量i
(function(i){
setTimeout(function () {
console.log(i)
}, 1000)
})(i)
解法3,利用let关键字
for (let i = 0; i < 10; i++) {
setTimeout(function () {
console.log(i)
}, 1000)
- 对于以下代码,本意是要每隔1秒输出0-9,但这段代码的效果却是1秒钟后,同时输出了0-9,如何修正?
for (let i = 0; i < 10; i++) {
setTimeout(function () {
console.log(i)
}, 1000)
解析:在js中先执行同步任务,再执行异步任务,setTimeout函数的第二参数,相对的是同步任务结束的那一刻, 而不是上一个异步任务结束的那一刻,所以,修正的方法是动态改变第二个参数。
for (let i = 0; i < 10; i++) {
setTimeout(function () {
console.log(i)
}, 1000*i)
参考资料: var和let/const的区别