一篇文章讲明白var let 和const的区别

134 阅读3分钟

最近在重温一些前端的基础知识,于是对看过的知识点进行归纳整理,防止老年痴呆看完就忘

let 和 const

先看结果,let 和 const 为ES6新增,与var的具体区别如下

区别varletconst
作用域全局和函数全局、函数、块级全局、函数、块级
变量提升XX
临时性死区X
重复声明XX
全局作用域下声明挂在window或global下不挂不挂
重新赋值X

关于作用域

  • 全局作用域
var a = 1;
let b = 2;
const c = 3;
console.log(a, b, c); // 1 2 3
  • 函数作用域
function test() {
    var a = 1;
    let b = 2;
    const c = 3;
    console.log('函数内', a, b, c); // 1 2 3
}
test();
console.log('函数外', a); // a is not defined
console.log('函数外', b); // b is not defined
console.log('函数外', c); // c is not defined
  • 块级作用域
{
    var a = 1;
    let b = 2;
    const c = 3;
    console.log('in block', a, b, c); // 1 2 3
}
console.log('块级外', a); // 1
console.log('块级外', b); // b is not defined
console.log('块级外', c); // c is not defined
  • 一个老生常谈的问题
// 输出5次5
for(var i = 0; i < 5; i++) {
    setTimeout(function() {
        console.log(i);
    }, 100);
}
// 通过闭包解决
for(var i = 0; i < 5; i++) {
    (function (i) {
        setTimeout(function() {
            console.log(i);
        }, 100);
    })(i);
}
// 通过let解决 
for(let i = 0; i < 5; i++) {
    setTimeout(() => {
        console.log(i);
    }, 100);
}
  • 同时,通过闭包还能定义私有变量
var $ = (function (window) {
    var a = 1;
    var b = 2;
    setTimeout(function() {
        console.log('闭包', a, b)
    }, 100);
    return {
        a,
        b
    }
})(window);
console.log($.a); // 1
console.log(a); // a is not defined
// 

变量提升

当我们定义一个变量的时候,JS引擎会分三个步骤,创建、初始化、和赋值

  • 对于var 代码如下
console.log(a, b); // undefined undefined
a = 1;
b = 2;
var a;
var b;
console.log(a, b); // 1 2
  1. 创建:先找出所有var声明的变量(a和b),并创建这写变量
  2. 初始化: 将这些变量初始化为undefined

这就可以解释就是指在引擎做了这两步为什么上面会输出undefined而不是报错;而通常我们所说的变量提升

  1. 开始执行代码
  2. 赋值:将a b赋值为1 2
  • 对于let
console.log(a); // a is not defined
let a = 1;
a = 2;
  1. 创建:找出所有用let声明的变量,并创建这些变量
  2. 开始执行代码
  3. 初始化:将a初始化为1,如果是let a,则是初始化为undefined
  4. 赋值:将a赋值为2

const和let类似,但是没有赋值这一步,二手在初始化的时候直接将其初始成初始只,后续则不能重新赋值

以上就可以解释为什么let和const为什么必须先声明后使用了

临时性死区

  • 对于var, 没有临时性死区
var a = 1;
{
    a = 2;
    console.log(a); // Cannot access 'a' before initialization
    var a;
}
  • 而对于let和const,一旦进入了如下的块级作用域,a变量就已经存在了(上面的变量提升的创建过程),此时必须等声明的那行代码执行完,才可以访问该变量
var a = 1;
{
    a = 2;
    console.log(a); // Cannot access 'a' before initialization
    let a; // 或const a = 3;
}

重复声明和重新赋值

  • let和const都不能重复声明,且const不能重新赋值
var a = 1;
var a = 2;
let b = 1;
let b = 2; //Identifier 'b' has already been declared
const c = 1;
c = 2; // Assignment to constant variable

全局作用域下定义变量

  • 如果在全局作用域下定义变量,对于var,则会被挂到全局对象(window|global)下,而对于const 和let则不会
var a = 1;
let b = 2;
const c = 3;
console.log(a, b, c); // 1 2 3
console.log(window.a, window.b, window.c); // 1 undefined undefined

写在最后,推荐使用const, 如果有需要重新赋值的则使用let