var、let和const的区别

129 阅读4分钟

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对象上。