ES6——let/const/var使用场景及区别

前言

let 和 const 是 ES6 中新增的命令,是用于解决 ES5 中使用 var 命令声明变量的一些问题而出现的,看一下 var 命令的一些不合理的问题。

var 的问题

var主要有如下几个不合理的地方:

  1. 没有块级作用域

  2. 重复声明

  3. 绑定全局作用域

  4. 变量提升

问题1:没有块级作用域
ES5 只有全局作用域和函数作用域,没有块级作用域。在ES6之前,最常见的修复方法是使用IIFE(Immediately Invoked Function Expression,意为立即调用的函数表达式,即声明函数的同时立即调用这个函数)。
eg:

for(var i=0;i<5;i++){
    setTimeout(function(){
        console.log(i);
    },1000)
} //5555

IIFE解决

for (var i = 0; i < 5; i++) {
​    (function(i) {
​        setTimeout(function() { 
​          console.log(i); 
​        }, 1000);
​    })(i);
}//01234

但是let和const的发明让我们有了一种更简单的修复方法。
不仅是在循环里引入了一个新的变量环境,而且还是针对每次迭代都会创建这样一个新作用域。 这就是我们在使用立即执行的函数表达式时做的事
let解决

for(let i = 0; i < 5; i++) {
    setTimeout(function() {
      console.log(i);
    }, 1000)
}

问题2:重复声明
var可以反复声明相同标识符的变量,在大多数语言中,在同一个作用域多次声明同一个变量是非法的,但是在 ES5 中使用 var 命令重复声明的没有任何问题的;而let是不允许的;
eg:

     var a = 1;console.log(a); //1
​    var a = 2;
​    console.log(a); // 2
​    var a = 3;
​    console.log(a); //3

问题3:绑定全局作用域
在全局作用域下通过 var 命令声明变量,会创建一个新的全局变量作为全局对象的属性
eg:

 `````var a = 1;
​     console.log(window)

问题4:变量提升
变量提升指的是变量声明的提升,不会提升变量的初始化和赋值,JavaScript会把作用域里的所有变量和函数提到函数的顶部声明
eg:

 console.log(foo) //undifined
 var foo = 123

foo其实已经在调用前被声明了,只是没有被初始化。
对于let来说,情况有点不同:
eg:

 console.log(aLet)  
// Uncaught ReferenceError: Cannot access 'aLet' before initialization
let aLet = 2

注:在let/const声明之前就访问对应的变量与常量,会抛出ReferenceError错误;但在var声明之前就访问对应的变量,则会得到undefined

根据ES6标准中对于let/const声明的章节13.3.1,说由let/const声明的变量,当它们包含的词法环境(Lexical Environment)被实例化时会被创建,但只有在变量(et/const)的词法绑定(LexicalBinding)已经被求值运算后(初始化),才能够被访问。
当程序的控制流程在新的作用域(module, function或block作用域)进行实例化时,在此作用域中的用let/const声明的变量会先在作用域中被创建出来,但因此时还未进行词法绑定,也就是对声明语句进行求值运算,所以是不能被访问的,访问就会抛出错误。所以在这运行流程一进入作用域创建变量,到变量开始可被访问之间的一段时间,就称之为TDZ(暂时死区)。

TDZ最一开始是为了const所设计的,但后来的对let的设计也是一致的。

以上面解说来看,以let/const声明的变量,也是会有提升(hoist)的作用。提升是JS语言中对于变量声明的基本特性,只是因为TDZ的作用,并不会像使用var来声明变量,只是会得到undefined而已,现在则是会直接抛出ReferenceError错误,而且很明显的这是一个在运行期间才会出现的错误。
eg:

 let x = 'outer value'
 (function () {
    // 这里会产生 TDZ for x
    console.log(x) // TDZ期间访问,产生ReferenceError错误
    let x = 'inner value' // 对x的声明语句,这里结束 TDZ for x
 }())

在例子中的IIFE里的函数作用域,变量x在作用域中会先被提升到函数区域中的最上面,但这时会产生TDZ,如果在程序流程还未运行到x的声明语句时,算是在TDZ作用的期间,这时候访问x的值,就会抛出ReferenceError错误。

const

特点

1.const一般只用于声明常量,声明的同时立即初始化(Missing initializer in const declaration语法错误)
eg:

const y; // Missing initializer in const declaration

2.声明的常量不能修改,否则会报错(Assignment to constant variable.(指定恒定变量。))
注:声明对象、数组(引用类型数据)的时候,对象的属性名和属性值都可以添加、修改,保证变量名指向的地址不变;不能重新指向另一个对象,不能重写对象。
eg:

 const x = 1; 
 x = 2;  // Uncaught TypeError: Assignment to constant()
 const obj = {
   name: 1
 }
 obj.name = 2;
 obj.name1 = 3;
 console.log(obj) //{name: 2, name1: 3}
 obj = { name: 3 } // Assignment to constant variable.

3.块级作用域
eg:

 {
  const age = 17;
 }
age; //ReferenceError: age is not defined

** 4.存在暂时性死区,只能在声明之后调用**

练习题:

1.1

let a;
const a

结果:

let a; // 不报错
const a // 报错  Missing initializer in const declaration

1.2

let user = {name:'Lucy',age:17};
const USER_INFO = user;
console.log(user)
console.log(USER_INFO)

user.age = 32;
console.log(user)
console.log(USER_INFO)

结果:

{name:‘Lucy’,age:17}
{name:‘Lucy’,age:17}
{name:‘Lucy’,age:32}
{name:‘Lucy’,age:32}

1.3

     let a = 'aaa';
​    console.log(a);  
​    console.log(window.a);  
​    var b = 'bbb';
​    console.log(b);  
​    console.log(window.b);  
​    c = 'ccc';
​    console.log(c);  
​    console.log(window.c);

结果:

   aaa
   undefined
   bbb
   bbb
   ccc
   ccc

1.4

var a = 1; 
b = 2; 
delete a; 
delete b;
console.log(window)

结果:
delete a; //使用var定义的变量,无法删除。原因:使用var语句添加的window属性有一个名为configurable的特性,其值被设置为false。
delete b;// 删除
delete window.c;// 删除

1.5

for (var i = 0; i < 3; i++) {
   console.log(i)
}
console.log(i)

for (let j = 0; j < 3; j++) {
   console.log(j)
}
console.log(j)

结果:

0 1 2
3

0 1 2
j is not defined

1.6

for (var i = 0; i < 3; i++) {
    let i = 'bbb';
    console.log(i);
}
for (let j = 0; j < 3; j++) {
    var j = 'aaa';
    console.log(j);
}

结果:
bbb
bbb
bbb
Identifier ‘j’ has already been declared.(已声明标识符“i”)
1.7

var a = [];
for (var i = 0; i < 10; i++) {
 console.log(i);
 a[i] = function () {
   console.log(i);  //执行此代码时,for循环已经执行完毕,i 的值是10
 };
}
a[6]();

结果:
0 1 2 3 4 5 6 7 8 9
10
1.8

for (var i = 1; i <= 5; i++) {
    (function() {
        setTimeout( function timer() {
            console.log(i);
        },i*1000 );
    })();
}

结果:
66666

相关面试题链接:
https://blog.csdn.net/qq_37024887/article/details/106784068

你可能感兴趣的:(es6)