LET、CONST 和 VAR 的区别

108 阅读3分钟

JS 中声明变量的几种方式

  1. ES5: var & function
  2. ES6: let & const & class & import

let vs const

ES6 中,class 和 import 都是有具体含义的,而 let 和 const 有什么区别呢?

有些人可能会认为, let 是声明变量的,const是声明常量的,这句话就大错特错了。

let 和 const 声明的都是变量,都是要存储到当前上下文的 VO / AO 变量对象中的。

二者的区别在于:

  1. let声明的变量,后续根据需求,可以改变"变量"和"值"之间的指针指向;而 const 不允许改变"变量"的指针指向;
  2. const 声明的变量必须要有初始值。

let 和 var

都可以声明一个值可变的变量,它们的区别如下:

  1. var 存在变量提升,而 let 或者 const 都不会
console.log(x); // undefined
console.log(y); // cannot assess 'y' before initialization

var x = 12;
let y = 13;

// 好处 更严谨 参见以下的函数表达式声明函数
// 「不存在变量提升,只能在创建函数以下使用函数」
// 「用 const 声明,后期不允许重构 fn」
const fn = function() {}  
  1. 全局上下文基于 var 声明的变量是直接存储到 GO 中的(window), 而 let 是存储到 VO(G) 中的,和 GO 没关系。
var x = 12;
let y = 13;
console.log(x, y); // 12 13
console.log(window.x, window.y); // 12 undefined
  1. var 允许重复声明「只不过浏览器只声明一次而已」,但是词法上是允许的,let/const 在词法上都不允许重复声明「错误发生在词法解析阶段」, 并且不论我们基于何种方式声明过这个变量(例如: var/function 再或者函数形参),let/const 声明都会报错!
// 不输出 ok 直接报错
console.log('ok');  // Uncaught SyntaxError: Identifier 'x' has already been declared
var x = 12;
let x = 13;

浏览器拿到从服务端获取的 JS 代码, 首先进行词法分析 (按照 ECMA262),分析完成的结果是一个 AST 语法树,然后浏览器底层 (比如 C++)程序按照生产的语法树一步步的去执行!这个过程比较复杂,后面单独写一篇文章来总结它。

  1. 在 JS 代码执行的过程中,如果花括号(排除对象和函数的)中出现 let/const/function/class 等关键词(切记:没有 var),则当大括号所在的代码块,会产生一个"私有块级上下文"。 var 不会产生块级上下文,而且块级上下文对他也没有任何的作用。

块级上下文 EC(BLOCK) 中有自己的变量对象,代码执行前会做以下几个事情。

  1. 初始化作用域链
  2. 初始化this
  3. 初始化 arguments
  4. 变量提升
  5. 代码执行
// console.log(a); // undefined
// console.log(b); // uncaught ReferenceError: bb is not defined
var a = 12;
let b = 13;

if (1 == 1) {
    // EC(BLOCK) 块级私有上下文 
    //    VO(BLOCK) // 私有变量对象
    //      let b = 200 执行后,在 VO 中 b ---> 200
    // 作用域链(有): <EC(BLICK), EC(G)> 上级上下文是看在哪指向代码产生的块级上下文
    // 初始化 THIS: 块级上下文没有自己的 this
    // 初始化 Arguments:  -
    // 变量提升(有):...
    // 代码执行(有):
    console.log(a); // 12
    // console.log(b); // ReferenceError: b is not defined
    var a = 100;
    let b = 200;
    console.log(a, b); // 100 200
}

console.log(a, b); // 100 13
  1. 暂时性死区
console.log(x); // VM3107:1 Uncaught ReferenceError: x is not defined

console.log(typeof x); // undefined  基于 typeof 检测一个未被声明的变量,结果是undefined,而不会报错。

再看下面这一段代码:

console.log(typeof x);  //  cannot assess 'y' before initialization
let x = 12;

这就是暂时性死区,在变量声明前不允许使用,也不允许在上面声明。