ES6——let和const

  这里主要介绍let和const的使用方法

  介绍两种新的声明对象的方法之前,先介绍ES6中新增的块级作用域

块级作用域

  可以简单理解为,用一对花括号括起来的区域即为块级作用域,例如forifswitch里的花括号,可以嵌套

  如果在全局环境下,默认也是一个块级作用域,不过这个块比较特殊,也就是不存在离开块级作用域的问题

  但创建对象时的一对花括号不算块级作用域

  

  子级块级作用域可以访问到父级块级作用域中的变量

  

   特别注意,for语句中的()也是一个块级作用域,而后面的{}则是()的子级块级作用域

  也就是说,可以在for语句的执行语句块中,访问到for语句()里用let声明的变量,而出了for语句则无法访问该变量

  

 

let

  上面也介绍了一些let的使用方法特色,即:

  1.作用于块级作用域中

  2.可以被嵌套于其内部的子级的块级作用域访问到

  此外,let和var两种声明方式还有以下的区别:

同一作用域中不可重复声明

  使用var可以在同一块级作用域多次声明同名的变量,且再次声明不赋值时,变量的值不变

  而使用let,只可以在同一块级作用域中声明一次同名变量,再次声明就会报错,在不同的块级作用域中不存在该问题

  let声明后没有赋值,默认该变量值为undefined

  

没有变量提升(不会被预解析)

  let声明的变量不会被有声明提前的现象,必须在声明后再调用,否则报错

  

暂存死区

  ES6中,let声明的同名变量在声明时产生一个封闭的作用域,其以下的子级块级作用域无法访问到该变量,这个现象即暂存死区

  

小案例

  可以利用let声明的块级作用域,造成和闭包同样的效果

for(let i=1;i<=10;i++){
    var btn = document.createElement("button");
    btn.innerText = i;
    btn.onclick = function(){
        console.log(i);
    }
    document.body.appendChild(btn);
}
let声明和按钮点击

 

const

  ES6中新增的另一种声明方法为const,可以用来声明常量

  这里的常量如果是基本类型,其值声明后不可改变

  如果是引用类型,则可以修改内部的属性方法,只要不修改其变量名指向的引用类型地址即可

  

  此外,const还和let有众多相同的特性,例如:

  1.同一块级作用域中,不可重复声明

  2.没有变量提升(没有预解析)

  3.只在当前的块级作用域中可以被访问到

引用类型属性修改问题

  如果用const声明引用类型,其属性值是可以改变甚至添加的

  如果不希望属性值和属性名改变,也不希望扩充新的属性名和属性值,需要用Object.freeze()方法

  

 

ES6之前声明常量的方法

  ES6中提供了const来声明常量,那ES6之前又是如何声明常量的呢?

Object对象的seal方法

  Object对象的seal方法,可以让声明过的对象无法扩展,即无法添加新的属性/方法,但可以修改已有的属性值

  

Object对象的defineProperty方法

  defineProperty方法可以传入三个参数:要修改的对象,要修改的属性名,要修改的属性值

  其中要修改的属性值可以设置其value()以及writable(是否可写),注意writable的属性设置是不可逆的(即后续无法再次重新设置)

  

  综上可以发现,Object对象的seal方法和defineProperty方法加起来才实现freeze方法(即对象属性不可扩展,同时对象属性不可更改)

  

 小案例

  用以上的seal和defineProperty方法,来封装一个同freeze功能相同的方法

  注意这里需要考虑到对象内部嵌套对象的可能性,需要用递归

//模拟freeze方法
//思路:传入一个对象,先遍历对象中的所有属性,让其每个属性的written都变成false
//最后对整个对象用seal方法,让对象不可扩展
function frozen(obj){
    //遍历整个对象
    for(let i in obj){
        //如果该属性值是对象,用递归,继续让其无法扩展和无法修改
        //修复函数类型可以被修改的bug
        if(obj[i] instanceof Object && typeof obj[i] != "function"){
            frozen(obj[i]);
        }
        //如果属性值不是对象,则设置其不可更改
        else{
            //需要明确属性值不是原型链上的
            if(obj.hasOwnProperty(i)){
                Object.defineProperty(obj,i,{
                    writable:false
                })
            }
        }
    }
    //最后对整个对象用seal让其不可扩展
    Object.seal(obj);
}

var xm = {
    age:18,
    name:"xiaoming",
    language:{
        chinese:"fluent",
        english:"master"
    },
    say:function(){
        console.log("hello");
    }
}
frozen(xm);

 

posted @ 2019-09-01 21:08  且听风吟720  阅读(315)  评论(0编辑  收藏  举报