关于const,let,var是一个再基础不过的问题了,然而就这基础的问题,总是没法在脑海里去形成一个体系的记忆。所以从今天开始,应该每天都要保持总结一个小点的习惯,来形成自己的知识体系。
说起var 与 let,const。首先对它的归类,我们需要知道
var 属于 es5
const let 属于 es6
下面就正式开始!
区别一:变量提升
在es5版本的项目,我们随处可以看见var的关键字,无论需要定义什么,一个var就搞定了,js弱语言的特性,使之会帮你判断定义的变量是一个什么样的基本类型。
es5版本,var与fuction关键字是存在变量提升的。js的引擎运行规则是,先解析代码,获取声明的变量,然后再一行一行的运行代码。被var定义的变量,会被提升到代码的头部,这时候就形成了变量提升,使之变量或者函数在未被声明之前,先使用不会出错。比如说:
var x = 1; // 声明 + 初始化 x
console.log(x + " " + y); // '1 undefined'
var y = 2;
那这相当于:
var x = 1;
var y = 2;
console.log(x + "" + y);
但是如果是换成let(换成const是相同的道理)
let z = 1;
console.log(z + "" + r);
let r = 3;
// r is not defined
也就说明,let,const是不存在变量提升的。在我看来,let,const更加符合代码从上至下的逻辑,也规范了代码的书写,在es6语法中,let,const就是用来取代var变量的。
区别之二:作用域
对于var而言,只有全局作用域和函数作用域。我们常说的局部作用域其实是指,变量在函数内则为局部作用域,那么该变量只能在函数内访问。如果变量不在函数内,则为全局变量。html中全局变量的作用域范围为windows(虽然我们平常很少用windows去点出来)
在es6之是没有块级作用域这么一说的。在es6中是存在的。
在我理解看来,var与const,let其实是少了块级作用域这么一说的。比如说:
{
var a = 1;
}
// 那么在这里应该不可以访问到a,可是这里可以,说明var是没有块级作用域这么一说的。
{
let a = 1;
}
// 这里不可以访问的,说明{}中,let定义的变量是受保护的。
当然说到了作用域,又不得不提到循环作用域。因为这个概念,又提到了立即执行函数的概念。
比如说:
var i = 5;
for (var i = 0; i < 10; i++) {
// 一系列的代码
}
console.log(i);
// 此时i为10;
因为var定义的变量是全局的,循环体内与外,都会受到影响的。
而对于let而言,又有如下的结果:
let i = 5;
for ( let i = 0; i < 10; i ++) {
// 一系列的代码
}
console.log(i);
// 此时i为5,可见,let对于局内与局外没有什么影响
区别之三:重新定义变量
使用var重新声明变量可能会带来问题,比如说在块级作用域去修改var定义的变量,那么可能会把全局的值给修改了。比如说:
var x = 10;
{
var x = 2;
}
// 这里输出x为2,如果存在相同的变量,及有可能把变量给误修改了
但是对于let而言,因为存在块级作用域,所以,重新定义变量,它的逻辑会比较清晰。
// 这里输出x为10
{
let x = 2;
// 这里输出x为2
}
// 这里输出x为10
当然,是用var定义的常量不可以再用let去声明了,这不符合规范。
注意,使用var,let我们都可以声明一个变量,可以不用给初始值。但是如果用const定义只能定义常量(不可修改),且必须有初始值。
比如说:
const a;
a = 1;
console.log(a) // SyntaxError: Missing initializer in const declaration
那么这个a在这里是不符合规范的。
又比如说:
const a = 1;
a = 2
console.log(a); //TypeError: Assignment to constant variable.
这也是不符合规范的,因为a使用const定义的常量,不可以再修改的。
但是如果是用const定义的对象,再去修改,会变成
const a = {};
a.x = '1'
console.log(a); // { x: '1' }
原因是因为const定义的对象,对象的指向地址并没有改变,const能保证的就是指针不改变,并不影响指向的内容。所以,使用const还是可以改变对象的。