var、let 和 const 都是 JavaScript 中用来声明变量的关键字,既然都是用来声明变量的,那它们之间有什么区别呢?在开发中如何选择呢?
1.产生的时机不同
var是最早的出现的,是ES5的语法,let和const都是ES6出现的。
JavaScript作为一种动态类型、弱类型的、基于原型的客户端脚本语言,
JavaScript由三部分组成:
- ECMAScript:是JS的核心部分,他规定了语言的组成部分,包括语法、语句、关键字、保留字、操作符、对象等等。ECMASccript是JavaScript的标准规范,JavaScript是ECMAScript的具体实现。
- DOM:文档对象模型,开发中我们就是借助DOM来操作页面中的元素
- BOM:浏览器对象模型,支持可以访问和操作浏览器窗口的浏览器对象模型,开发人员可以控制浏览器显示的页面以外的部分。
ES5是ECMSScript的第五个版本,ES6是ECMSScript的第6个版本,ES6是向下兼容的。
我们都知道存在即有一定的道理,let和const的出现解决了什么问题呢?
2. var有变量提升(Hoisting)的特性
变量提升:在全局作用域中或者在局部作用域中,使用var关键字声明的变量,都会被提升到该作用域的最顶部。
先看代码
console.log(aa);
var aa = 11;
console.log(aa);
// result: undefined, 11
在编码中正常的思维是先定义后调用,第一行的输出aa变量为什么没报错呢?这就是因为有变量提升,即JavaScript引擎在预编译的时候,会将所有var声明的语句自动放在当前作用域的最顶部,注意这里只是将声明提前,并未初始化,所以输出是undefined,不是11,也不是报错。
上面的语句就相当于:
var aa;
console.log(aa);
aa = 11;
console.log(aa);
2.1 那么JS变量提升会带来哪些问题呢?
先看代码
var tmp = 'hello world';
for (var i = 0; i < tmp.length; i++) {
console.log(tmp[i]);
}
console.log(i); //11
观察以上代码,由于我们使用var定义了循环变量i,但是i一直没有销毁,在代码越来越复杂的情况下,可能我们已经忘记了上面有已经能存在了一个全局变量i,会出现意想不到的结果,且比较难以排查。
其实这里我们只是需要一个循环变量,不必是全局变量,且只需要在该循环体中有效,不会对全局的变量造成污染,这里就是ES6出现的原因之一,ES6解决了这个问题。
这里总结一下,变量提升带来的优点和缺点:
优点:
- 解析和预编译过程中的变量提升可以提高性能,可以预先给变量分配栈空间
- 可以在任何地方引用全局变量,方便编写,不必担心代码的执行顺序
缺点:
-
变量提升造成代码难以理解、维护和调试,增加了代码阅读的复杂度
-
可能会对外部变量造成污染,很多地方我们并不需要全局变量
3.块级作用域、let和const
为了解决上述问题,ES6应运而生,ES6中定义了块级作用域、let、const。
3.1 块级所用域
ES5只有全局作用域和函数作用域。
先看代码^-^
var txt = '这是外层变量';
function fn() {
console.log(txt);
if (false) {
var txt = '这是函数内层变量';
}
}
fn();//undefined
观察以上代码,为何会打印undefined,就是因为函数内部var声明的txt变量进行了提升,提升到了函数内部的顶部,当执行到代码第4行时,会先从当前作用域(函数作用域)寻找,只有在当前作用域找不到的情况下,才会去上层(全局作用域)寻找,因为变量提升结果在当前作用域找到了txt变量(已声明但未初始化),这里即是内层变量的声明覆盖了外层变量。
所以ES6定义了块级作用域。
再看代码^-^
let txt = '这是外层变量';
function fn() {
console.log(txt);
if (false) {
let txt = '这是函数内层变量';
}
}
fn();//这里外层变量
块级作用域中let声明的变量只在该作用域有效.
3.2 let和const
let、const声明和var声明用法一样,不同点在于let、var声明的是变量,const声明的是常量。var存在变量提升,let、const不存在变量提升。
先看代码^-^
let声明变量的一些情况
{
console.log(a); //报错 Unexpected identifier 'Uncaught'
let a = 1;
console.log(a); //1
}
console.log(a)// 报错,Unexpected identifier 'Uncaught'
var a = 1;
let a = 1; //不能重复声明 报错 Identifier 'a' has already been declared
var a1 = 1; //全局作用域
{
let a1 = 1; // 代码块中可以同名变量
}
let a = 1;
console.log(window.a); //undefined,let声明的变量不属于windows对象
const声明变量的一些情况
const声明的是常量,常量不可以修改。常量定义必须初始化值,如果不初始化值就会报错。特别注意的一点是const变量不能修改指针,但是可以修改值,比如我们定义一个对象,我们就可以修改对象里的属性值,但是不能重写整个对象
{
console.log(a); //报错 Unexpected identifier 'Uncaught'
const a = 1;
console.log(a); //1
}
{
const a = 1; console.log(a); //1;
}
console.log(a);// 访问不了内部变量,报错 Unexpected identifier 'Uncaught'
const a;
console.log(a);//常量a未初始化 报错 Missing initializer in const declaration
const a1 = { b:1,c:2 };
a1 = {}; //不能修改对象指针, 报错 Assignment to constant variable
const a2 = { b:1,c:2 };
a2 = {b:2,c:1}; // Uncaught TypeError: Assignment to constant variable.
const a3 = 1;
console.log(window.a3); //undefined
const声明必须赋值才能使用,常量值不可修改,对象可以修改值,不能修改指针。const变量不会挂载到windows对象上。