var、let、const 区别

164 阅读3分钟

要说清楚 var、let、const 三者的区别,就要从变量提升 Hoisting 和 JavaScript 引擎访问变量时的生命周期说起,且听我慢慢道来...


Hoisting(变量提升)

变量和函数的声明会在编译阶段放入到内存中,给人的感觉就是其声明会移动到整个代码的最顶部。


变量生命周期

JS 引擎访问变量时其生命周期包括如下三个阶段:

  1. 创建阶段:在作用域中注册一个变量
  2. 初始化阶段:分配内存,给作用域中的变量创建绑定,变量会自动初始化为 undefined
  3. 赋值阶段:给已经初始化的变量赋值

var

var 声明的变量,有两个点与 let 和 const 有区别:

  1. 是用 var 声明的变量会成为 window 对象的属性。

    我们可以在 chrome 浏览器的 console 下验证:

    var a = 1;
    window.a;    // 1
    let b = 1;
    window.b;    // undefined
    const c = 1;
    window.c;    // undefined
  1. 创建阶段初始化阶段被提升,所以你能看到如下代码是可以执行但不会报错的并且返回的结果为 undefined:
    console.log(a);    // undefined
    var a = 1;

为什么不是 1 呢?因为只有创建阶段和初始化阶段被提升了,而赋值阶段不被提升,上面代码相当于如下代码:

    var a = undefined;    // 创建阶段 + 初始化阶段
    console.log(a);
    a = 1;                // 赋值阶段

let

关于 let ,我查阅了许多资料,就是想知道用 let 声明的变量到底会不会变量提升,答案是:会

let 声明的变量将在创建阶段就被提升,让我们用代码来证明:

第一阶段:xxx is not defined

    console.log(a);

当我们直接打印一个变量时,会报 a is not defined,原因就是该变量创建都没有创建,当前作用域中没有注册该变量。

第二阶段:ReferenceError: Cannot access 'a' before initialization

    console.log(a);
    let a;

该阶段可以证明 let 是存在变量提升的,如果不存在变量提升,我们看到的应该如第一个阶段所示的 a is not defined,但这里却显示的是ReferenceError: Cannot access 'a' before initialization,翻译一下就是引用错误,在 a 初始化之前我们不能使用 a ,也就是说 let 声明的变量在创建阶段的时候就被提升了,但是不会像 var 那样也提升初始化阶段,除此之外,用 let 声明会产生暂时性死区,这就使得我们不能再用 let 声明完之后又去声明同名的变量。比如:

    let a = 1;
    var a = 1;

结果:SyntaxError: Identifier 'a' has already been declared

第三阶段:undefined

    let a;
    console.log(a);

倘若我们将 let a; 放置在打印语句的前面,那么相当于执行了:

    // 创建一个变量:a
    // 初始化值为 undefined
    let a;
    console.log(a);

通过上述几个阶段的讨论,我们不仅能知道 let 声明的变量确实存在变量提升 Hoisting 并且会产生暂时性死区,还顺带知道了与 var 的区别。


const

const 与 let 声明变量的机制非常类似,只不过我们必须在声明的时候就指定它的值,因为 const 声明的是一个常量,以后是不能修改的,所以必须声明时就指定值。

用 const 声明创建一个常量,其作用域可以是全局或本地声明的块。 但是与 var 变量不同,全局常量即 const 声明的变量是不会变为 window 对象的属性,这个在 var 那里已经验证过了。


function

这里再简单介绍下 function 的变量提升,function 在创建、初始化、赋值阶段时都存在变量提升。