ES6基础--ES6概述、let和const命令

目录

ES6概述

let和const命令

let命令

const命令 

使用特点


        前面我们声明变量、定义函数等等都是基于ES5的基础之上

ES6概述

        ES6全称是ECMAScript6.0,是JavaScript的下一个版本标准。ECMAScript和JavaScript的关系可以这么理解:前者是后者的规格,后者是前者的一种实现

        ES5主要是为了解决ES5的先天不足,例如ES5中没有类的概念,也没有块级作用域等等,这些ES6都有很好的弥补不足。

let和const命令

        这两个命令在之前的博客-作用域详解中我们有提到过,这里再做一个系统性的总结,区分var命令,之前的博客:

JavaScript基础--作用域详解_zxn200125的博客-CSDN博客

let命令

        let命令的用法类似于var,不同点在于声明的变量只在let命令所在的代码块内有效。

{
    let a = 1;
    console.log(a);  //1
}
console.log(a);   //ReferenceError: a is not defined

        我们可以对比一下var输出和let输出:

var a = [];
for(var i = 0;i<5;i++){
    a[i] = function(){
        console.log("var输出",i);  
    };
}
a[3]();       //var声明输出 5

var b = [];
for(let j = 0;j<5;j++){
    b[j] = function(){
        console.log("let输出",j);  
    };
}
b[3]();      //let声明输出 3

         如上例,变量i是var变量声明,是一个全局变量。当函数内循环完之后,i输出的是最后一轮的值i=5,所以最终全局变量i为5。变量j是let变量声明的,是局部变量,只在本轮循环有效,也就是每一轮的循环变量j都是一个新变量。

const命令 

        constlet的区别在于,const声明的是一个只读的常量,声明之后常量的值不能被改变。所以const声明的变量不能只声明不赋值。

//const正确声明和使用
const a = 10;
console.log(a);  //2

//改变const声明常量的值--报错
a = 2;
console.log(a);  //TypeError: Assignment to constant variable.

//const声明不赋值--报错
const b;  //SyntaxError: Missing initializer in const declaration

        const的本质不是保证变量的值不改动,实则是保证变量指向的内存地址所保存的数据不得改动。因此对于基本类型数据,值就保存在变量指向的内存地址,也就相当于常量。但是对于引用数据类型的数据,变量指向的内存地址,保存的只是一个指向实际数据的指针。那么这个时候,const只能保证这个指针是固定的,但是它指向的数据结构就是可变的了。因此声明一个常量的时候,要先考虑到指向的数据是什么类型。

//声明一个对象为常量
const obj = {};   
//在对象obj内添加属性--可行
obj.a = 1;
console.log(obj);  //{ a: 1 }

//将对象obj指向为另一个对象--报错
obj = {};         //TypeError: Assignment to constant variable.

        如果我们想要冻结对象,就可以使用Object.freeze()方法

//冻结对象
const obj = Object.freeze({});
obj.a = 1;
console.log(obj);   //{}

         上例中,常量obj指向的就是一个冻结的对象,因此添加新属性就不起作用。但是该方法不能冻结多层对象:

const obj = {
    a:10,       
    num:{
        b:20
    }
}
Object.freeze(obj);   //冻结obj对象
obj.a = 1;
obj.num.b = 2;
console.log(obj);  //{ a: 10, num: { b: 2 } }

        很显然,上例中我们发现属性a不能被修改,但是属性b还是被修改了,没有被冻结,那么要想解决此问题,达到冻结多层对象的效果,我们可以这么做:

const obj = {
    a:10,       
    num:{
        b:20
    }
}
function deepFreeze(obj){
    Object.freeze(obj);
    for(let key in obj){
        if(obj.hasOwnProperty(key) && typeof obj[key]==='object'){
            deepFreeze(obj[key]);
        }
    }
}
deepFreeze(obj);  //冻结obj对象
obj.a = 1;
obj.num.b = 2;
console.log(obj);  //{ a: 10, num: { b: 20 } }

         通过上述代码可以看出,我们封装一个deepFreeze函数,内部通过for...in遍历对obj对象中的所有属性进行冻结,如此达到冻结多层对象的效果。【hasOwnProperty()方法我们有在之前的博客对象object详解中提到过,这是一个内置对象,作用是指示对象自身属性中是否具有指定的属性】

使用特点

1.只在声明的块级作用域内有效

        这个在上面let命令中我们已经演示过了,这里就不多加赘述

2.不允许重复声明

        我们知道使用var变量时,可以重复声明,之后声明的值会覆盖之前声明的值。但是letconst不允许重复声明,重复声明会报错。

//var重复声明
var a = 1;
var a = 2;
var a = 3;
console.log(a);  //3

// let重复声明--报错
let b = 1;
let b = 2;
console.log(b);  //SyntaxError: Identifier 'b' has already been declared

var c = 1;
let c = 2;
console.log(c);  //SyntaxError: Identifier 'c' has already been declared

        所以同样,不能在函数内重新声明参数,但是若函数内还有一个子函数或者其他块级作用域,就可以进行声明,相当于外部函数是一个父作用域,内部其他块级作用域是一个子作用域。

//函数内重新声明参数--错误
function Fun(arg){
    let arg = 1;
    console.log(arg);
}
Fun();  //SyntaxError: Identifier 'arg' has already been declared
//参数内的块级作用域声明参数--正确
function Fun(arg){
    {let arg = 1;
    console.log(arg);}
}
Fun();   //1

         故let和const命令在函数内和循环内使用就非常合适,需要注意的是,在for循环内,有一个地方需要注意:

for(let i=0;i<5;i++){
    let i = 10;
    console.log(i);  //10 10 10 10 10
}

        我们发现,在for循环内用let两次对i进行声明赋值,但是没有报错,并且输出的是第二次声明的值。这是因为,在for循环中,设置循环变量的该部分是一个父作用域, 循环体内部是一个单独的子作用域,也就是这两个作用域是单独的,不是同一个作用域,所以不是两次声明赋值。

3.不存在变量提升

        在下面这篇博客我们有总结过,var关键字声明的变量存在变量提升情况。letconst命令就不存在这种情况,也就是说let所声明的变量和const所声明的常量一定要在声明之后使用

JavaScript基础--预解析详解_zxn200125的博客-CSDN博客

//var声明变量
console.log(a);   //undefined
var a = 1;   
//let声明变量
console.log(b);   //ReferenceError: Cannot access 'b' before initialization
let b = 2;
//const声明常量
console.log(c);   //ReferenceError: Cannot access 'c' before initialization
const c = 3;

 4.存在暂时性死区

        若块级作用域中存在let命令,它所声明的变量就绑定在这个区域,不受外部影响。若在这个块级作用域之前,在外部同样声明相同的变量,因为该变量已经绑定了块级作用域,在使用let命令声明该变量之前,该变量都无法使用。这就称之为“暂时性死区”。const如是,我们使用let进行测试了解:

var a = 10;
if(1){
    a = 20;
    let a;
}
console.log(a);  //ReferenceError: Cannot access 'a' before initialization

        上例中,我们先声明了一个全局变量a,然后在一个块级作用域中对a进行重新赋值,再使用let进行声明,结果a无法输出,这就是暂时性死区导致的结果。我们进行仔细分析: 虽然我们生命了全局变量a,但是块级作用域中又用let声明了一个局部变量a,所以变量a绑定在了这个局部作用域内。因此在let声明变量之前,对于a的赋值都会报错。

        因此,若区块中存在letconst命令,这个区块对这些命令声明的变量会形成封闭作用域,若在声明之前使用这些变量会报错。

var a = 10;
if(1){
    let a;
    console.log(a);  //undefined

    a = 20;
    console.log(a);  //20
}
console.log(a);      //10
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值