相比ES5中单一的var定义变量方式,ES6发展成var、let、const三种,前端人员在面试时也经常被问到let和var的区别,这里参考了阮一峰老师的es6和其他博文对这三种命令简单总结一下,如有错误欢迎指正,与君共勉。
1. 为方便后面的理解,这里先简单介绍一下作用域,我对作用域的理解是,
只会对某个范围产生作用,而不会对外产生影响的封闭空间。在封闭空间里,外部不能访问内部变量,但内部可以访问外部变量。2. js中的作用域有:
(1)ES5里只有两种作用域:全局作用域和函数作用域,且函数作用域内声明的变量由于存在hoisting,它的有效范围是整个函数体,如果对下面代码的输出结果有疑问,可结合JavaScript基础——ES5变量提升(Hoisting)理解。
//定义全部变量 var a=2; //定义外部函数 function outer(){ //访问全部变量 console.log(a); //定义内部函数 function inner(){ console.log(a); var a=10; console.log(a); } inner(); console.log(a); } outer(); //输出结果: 2 undefined 10 2(2)ES6除了上面两种,还新增了块级作用域,即最近的花括号所涵盖的范围。
注意:对类似 a=10; 这种给尚未声明的变量赋值的语句,会使得该变量a自动成为全局变量。但在"use strict"定义的严格模式下,不允许使用未声明的变量。
如图,本文总结了var和let的5点区别,分别是:块级作用域、变量提升、暂时性死区、重复声明和window全局访问。
let声明的变量b作用域为块级,因此在花括号之外访问会报错,而var声明的变量a最小的作用域也是函数作用域,因此可以正常输出。
由于var变量具有变量提升的特性,因此变量可以先使用后声明,而let所声明的变量一定要在声明之后使用,示例如下:
console.log(a); var a=1; //输出结果: undefined console.log(b); let b=2; //输出结果: ReferenceError只要块级作用域内存在let、const命令,它们所声明的变量就绑定这个区域,不再受外部的影响。并且该区域内,使用let或const命令声明变量之前,该变量都是不可用的,我们把这种语法称为暂时性死区。
示例一:
var tmp=1; if(true){ tmp=2; //ReferenceError let tmp; }let声明的变量tmp需要先声明再使用,因此上面的代码报错。
示例二:
if(true){ // TDZ开始 tmp=1; console.log(tmp); //ReferenceError let tmp; //TDZ结束 console.log(tmp); //undefined tmp=2; console.log(tmp); //2 }上面这段代码,在let对变量声明之前,都属于tmp的“死区”,会出现ReferenceError.
当用var重复声明变量时,变量只会在最顶部开始的地方声明一次,后面的声明都会被忽略,仅用于赋值。
var a=1; console.log(a); if(true){ var a=10; console.log(a); } console.log(a); //输出结果: 1 10 10let不允许在相同作用域内,重复声明同一个变量,也不能在函数内部重新声明参数。
//抛出语法错误:SyntaxError function func(){ let a=1; var a=2; } //抛出语法错误:SyntaxError function func(){ let a=1; let a=2; }也就是说,不能通过window.变量名的方式访问该变量
ES6中新增了const关键词,const就是用来定义常量的,常量名习惯大写,遵循的规则有,
const声明的常量不得改变值声明的同时,必须初始化赋值和let一样:块级作用域+没有hoisting+TDZ+不可重复声明