es6里面新增了两个声明变量的方法,一个是let,用于声明变量。一个是const,用于声明常量。var、let和const的区别经常会被面试官问到,大多数人都可能回答的是作用域和变量提升这两方面的不同,但你们知道内在原理吗?

下面我们就从声明过程内存分配变量提升三个方面来看一下这三者之间的区别。

声明过程

var

遇到有var的作用域,在任何语句执行前都已经完成了声明和初始化,也就是变量提升而且拿到undefined的原因由来。

通过下面示例可以看到变量a的声明跑到console.log的前面去了,只是赋值还是在console.log之后进行赋值的,console.log得到的结果就是undefined. 这就是所谓的变量提升了。

console.log(a); // undefined
var a = 10;

// 变量提升后
var a; // 声明并初始化
console.log(a); // a未赋值返回undefined
a = 10; // 赋值

let

解析器进入一个块级作用域,发现let关键字,变量只是先完成声明,并没有到初始化那一步。此时如果在此作用域提前访问,则报错xx is not defined,这就是暂时性死区的由来。等到解析到有let那一行的时候,才会进入初始化阶段。如果let的那一行是赋值操作,则初始化和赋值同时进行。

let初始化赋值之前访问,就会报错未定义变量

console.log(b); // b is not defined
let b = 20;

const

const、class都是同let—样的道理。const声明的是一个常量,常量是不可修改的,在没有完成初始化和赋值操作是访问会报错,不能重复声明同一个常量。

内存分配

var

var的话,会直接在栈内存里预分配内存空间,然后等到实际语句执行的时候,再存储对应的变量,如果传的是引用类型,那么会在堆内存里开辟一个内存空间存储实际内容,栈内存会存储一个指向堆内存的指针

let

let的话,是不会在栈内存里预分配内存空间,而且在栈内存分配变量时,做一个检查,如果已经有相同变量名存在就会报错 Identifier ‘变量’ has already been declared

如果用let重复声明同一个变量,那么这时候就会报错:变量b已经被声明了

let b = 10;
let b = 20;//error : Identifier 'b' has already been declared

const

const的话,也不会预分配内存空间,在栈内存分配变量时也会做同样的检查。不过const存储的变量是不可修改的,对于基本类型来说你无法修改定义的值,对于引用类型来说你无法修改栈内存里分配的指针,但是你可以修改指针指向的对象里面的属性

const声明的常量是不可以直接更改的,一旦你尝试着去修改一个常量的时候,浏览器就会告诉你,常量不可以被修改!

const c = 3.1415926;
c = 123;//error : Assignment to constant variable

变量提升

let const和var三者其实会存在变量提升

let只是创建过程提升,初始化过程并没有提升,所以会产生暂时性死区。

var的创建和初始化过程都提升了,所以在赋值前访问会得到undefined

function的创建、初始化、赋值都被提升了

function:声明、初始化、赋值一开始就全部完成,所以函数的变量提升优先级更高。