在搞清楚它们之间区别之前我们首先搞清楚它们作用域的不同之处。
首先var是ES5提出声明变量的关键字,而在ES5中只有作用域分为全局作用域和函数作用域两种;const和let则是ES6新提出用于定义变量和常量的关键字,同时也新增了块级作用域这个概念。举个最通俗易懂的例子
for (var i = 0; i < 3; i++) {
setTimeout(() => {
console.log(i);
}, 1000)
}
如果是按照我们一贯的想法,认为应该是会输出1、2、3,然而实际上控制台输出了三次3。这和我们想的有些不一样,之所以造成这种现象的其实是var在搞鬼。
因为在循环结束后此时i的值已经变为了3,而定时器还没到时间,同时因为用var定义的i是在全局作用域内,所以定时器里的i取到的都是最后的i值,所以打印的是同样的数。
为了解决由var引起的类似问题,所以ES6中有了const和let
var和let、const的区别
- var声明的变量,不存在块级作用域的概念, 可以跨块级作用域访问;const和let声明的变量常量,只能在块级作用域内访问,不能跨块级作用域访问。
- var存在变量提升(声明的变量被提升到该作用域的最顶部),const和let不存在变量提升(也有一种说法是认为存在提升,与var不同的是只提升创建过程,初始化不提升)。
- var可以重复多次声明,let和const则不允许重复声明
- var在声明的全局变量会挂载在window对象上,可以通过window.变量名的方式访问这些变量常量;而const和let声明的变量则不会有这一行为。
var声明
如果在某个函数内使用var 声明一个变量,则这个变量就属于当前的函数作用域,如果不是在任何函数内声明的,则这个变量就属于全局作用域。
代码演示:
var a = 1; // 此处声明的a为全局变量,全局作用域内均可访问
function fn() {
var b = 11; // 此处声明的b为局部变量,只有函数内可访问
console.log(a); // 1
console.log(b); // 11
}
fn()
console.log(a); // 1
console.log(b); // undefined
如果在不使用var直接声明变量的话,则该变量就会变成全局变量。
代码演示:
a = 1;
function fn() {
console.log(a); // 1
}
fn()
console.log(a); // 1
const声明
const就是用来定义常量的,只能初始化,不能重复赋值,所以const声明常量时必须赋初始值。
以下都为错误的用法:
const a = 1;
a = 2; // 重新赋值
const a; // 未设置初始值
const a = 1;
const a = 2; // 多次声明赋值
但是const也有特殊情况,内容可以改变。
如:
const obj = {
name: "xx",
age: 11
}
obj.age = 22
console.log(obj.age); // 22
这是因为对象是引用数据类型,const定义的obj中保存的是对象的地址,而我们修改对象属性时并没有修改对象地址,所以const定义对象的属性的改变是允许的。
像下面这种直接改变整个对象显然就会发生错误:
const obj = {
name: "xx",
age: 11
}
obj = {
name: "xx",
age: 22
}
console.log(obj.age); // Assignment to constant variable
let声明
let则就相当于var的升级版,改进了var的许多缺点。
如具有块级作用域:
此时将上面例子中的var改为let,则就能如我们所愿的打印 0 1 2
for (let i = 0; i < 3; i++) {
setTimeout(() => {
console.log(i); // 0 1 2
}, 1000)
}
还有和const一样不能重复定义
因此最后推荐大家,除特殊情况外尽量用const和let定义常量变量,以免出现一些不必要的问题。