1. let 和 const命令

152 阅读4分钟

块级作用域

在ES6中,使用let来代替var来声明变量,只在所在的块内有效,在块以外是找不到的

{
var a = 10;
let b = 20;
}
console.log(a); // 10
console.log(b); // b is not defined

let声明不存在变量提升

var声明的变量可以在声明的代码之前被查询到,值为undefined,而let是无法在声明和赋值以前被找到,会直接报错

var a;//js解释器会把下方的变量'a'被提到了代码最上方提前声明
console.log(a) // undefined
var a = 10;
//---------------------------------
let b;//手动写到上方 Identifier 'b' has already been declared.-标识符“ b”已被声明
console.log(b) // Cannot access 'b' before initialization.初始化前无法访问“ b”
let b = 20;

不允许重复声明

var的声明方式,是可以多次对一个变量进行声明并覆盖的,代码过多,失误会导致前面的同名变量出现问题,let就解决了这个问题,如果一个变量用let同一个作用于内重复声明就会直接报错

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

let b = 10;
let b = 20;
Identifier 'a' has already been declared // 标识符‘a’已被声明

function fn(c){
    let c;  //Identifier 'c' has already been declared. 标识符‘c’已被声明
}

const声明特性

const一旦被声明,就无法再次被修改 ( 被声明同时需要立刻赋值,只声明不赋值就会报错 )

const a;//Missing initializer in const declaration.const声明中缺少初始化程序
const a = 10;
      a = 20; //Assignment to constant variable.被分配到了不变的变量(常量)

const声明的对象同样不可以重复声明,直接修改常量对象,但是可以通过 对象名.对象属性 = '对象值' 进行修改和增加内部的属性和值

const person = {
    name:'x'
}
person.name = 'y';
console.log(person.name) // 打印结果 name:'y'

person.age = 'y';
console.log(person)//打印结果  {name: "x", age: "y"}
//-----------------------------------------------------
const person = {
    name:'x';
}
person = {
    name: 'y'//Assignment to constant variable.被分配到了不变的变量(常量)
}
person = {
    age: 'y'//Assignment to constant variable.被分配到了不变的变量(常量)
}

暂时性死区

在代码块儿内,使用let声明变量之前,这个变量名都是不可用的,被提前赋值就会报错,这在语法上,被称为暂时性死区(temporal dead zone,简称TDZ)

{
    //TDZ开始
    a = 10; //不会报错
    console.log(a);  //a = 10;
    
    //TDZ结束
	let a; //一旦在下方let a; 就会报错
    	   //Cannot access 'a' before initialization(初始化前无法访问“ a”)
    a = 20;
    console.log(a) //a = 20;
}

为什么使用块级作用域***

原因一:内层变量会覆盖外层变量

因为var可覆盖的特性,导致内层变量可能会覆盖外层变量,用let声明,let的值就会只存在于{ }的块级作用域内,不会覆盖外部 a 的值

var a = 20;
if (1 === 1) {
    var a = 40;
}
console.log(a); //打印结果 a = 40
//--------------------------------------
var a = 20;
{
    let a = 40;
}
console.log(a); //打印结果 a = 20;
原因二:用来计数的循环遍历泄露为全局变量

由于var声明的变量提升导致i被声明到了循环之外,循环结束后的结果10被保留到了i,会导致循环函数出现问题

var arr = []
var i;//var变量提升,从for循环被提到了上面
for(var i = 0; i < 10; i++){
    arr[i] = function(){
        return i;
    }
}
console.log(arr[5]());//打印结果为10
console.log(i) //打印结果为10

使用let循环以后i只存在于循环内,i不会暴露为全局变量

const arr = []
for(let i = 0; i < 10; i++){
    arr[i] = function(){
        return i;
    }
}
console.log(arr[5]());//打印结果为5
console.log(i) //i is not defined

*用闭包的方法解决var变量提升

var arr = []
for(var i = 0; i < 10; i++){
    arr[i] = (function(n){
        return function(){
            return n;
        }
    })(i)
}
原因三:不会污染全局变量
var RegExp = 10;
console.log(RegExp); //打印结果 10
console.log(window.RegExp); //打印结果 10
//------------------------------------------------
let RegExp = 10;
console.log(RegExp); //打印结果 10
console.log(window.RegExp); //打印结果 ƒ RegExp() { [native code] } √√√√√√√√√√

相同点:

  • 块级作用域
  • 暂时性死区
  • 不可被重复声明

使用建议: 默认情况下使用const,只有在知道变量值会被修改的时候使用let声明变量