zoukankan      html  css  js  c++  java
  • ES6基础入门之let、const

    以前变量的声明,可以通过var或者直接使用

    直接使用相当于往window全局对象上挂了一个属性

     

    let和var的主要区别:

    let声明的变量只在当前(块级)作用域内有效

    let声明的变量不能被重复声明

    不存在变量提升 

    ES6之前的作用域:

    全局作用域  函数作用域  eval作用域

    ES6块级作用域:

    所有用花括号包裹的代码块,如:

        if(){}
        for(){}
        switch(){}
        try{}catch(e){}
        {}

     但是不包括对象,如下面这种情况不是块级作用域

    var obj={
    
        
    }
    {
        var a=1;//不受块级作用域影响
        let b=2;//只作用在块级作用域内
    }
    console.log(a);
    console.log(b);

     块级作用域可以嵌套

    内层可以访问外层,外层不能访问内层

    {
        let a=1;
        {
            let b=2;
            console.log(a);
        }
        console.log(b);
    }

    使用let或者const声明的变量,不能再被重新声明

    var a=1;
    var a;
    console.log(a);//1  不会是undefined
    var a=2;
    console.log(a);//2
    
    let c=1;
    let c;//报错

    let不存在变量提升

    var是存在变量提升的,比如下面这段代码

     由于变量提升会把声明提前,相当于

     因此结果是undefined

     如果是let,不存在变量提升,因此会报错

    暂存死区:

     

     ES6规定,如果在一个作用域中存在let或者const声明的变量,那么会形成一个封闭作用域,因此会拿不到外面的变量

     

    使用let实现面试常见小例子

    生成10个按钮,每次点击弹出1-10

    使用var来实现

    for(var i=0;i<10;i++){
        (function(i){
            var btn=document.createElement("button");
            btn.innerText=i;
            btn.onclick=function(){
                alert(i);
            }
            document.body.appendChild(btn);
        })(i);
    }

    使用let来实现(不再需要闭包来实现内部的作用域)

    for(let i=0;i<10;i++){
        let btn=document.createElement("button");
        btn.innerText=i;
        btn.onclick=function(){
            alert(i);
        }
        document.body.appendChild(btn);
    }

    效果

    const 声明常量-不可改变的量

    常量必须在声明的时候赋值

    跟let一样,不能重复声明,存在块级作用域,不存在变量提升

    但是,当常量为引用类型的时候,是可以被修改的(不能修改引用地址,但是可以修改地址中的值)

    对象:

    const cyy={
        name:"cyy",
        age:18
    }
    console.log(cyy);
    cyy.name="cyy2";
    console.log(cyy);//可以修改引用地址里的值
    cyy={};
    console.log(cyy);//不能修改引用地址

    数组:

    const ARR=[];
    ARR.push(1);
    console.log(ARR);//可以修改引用里的值
    ARR=[];
    console.log(ARR);//不可以修改引用地址

    怎么防止常量为引用类型的时候能被修改的情况:

    Object.freeze()

    const cyy={
        name:"cyy",
        age:18
    }
    console.log(cyy);
    Object.freeze(cyy);//禁止对象常量的值被修改
    cyy.name="cyy2";
    console.log(cyy);//可以修改引用地址里的值

    const ARR=[];
    Object.freeze(ARR);
    ARR.push(1);
    console.log(ARR);//可以修改引用里的值

    const扩展

    ES6之前怎么声明常量

    1、假装是常量

    var CYY="cyy";

    2、给对象设置不可修改的属性

    Object.defineProperty

    var cyy={};
    Object.defineProperty(cyy,"BASE_NAME",{
        value:"cyy",
        writable:false
    })
    cyy.BASE_NAME="cyy2";
    console.log(cyy.BASE_NAME);

    可以看到BASE_NAME属性并没有被更改

     使用Object.defineProperty,并给属性设置writable:false,能让属性不可被修改;但是对象是可以新增属性的

    同理,如果是在全局范围内定义一个常量,就可以挂载到window上

    Object.defineProperty(window,"BASE_NAME",{
        value:"cyy",
        writable:false
    })
    BASE_NAME="cyy2";
    console.log(BASE_NAME);

    但是这样定义的常量,依然可以新增属性

    下面代码是给window对象的BASE_NAME属性设置了不可修改,但是还是可以给window对象上新增属性

    Object.defineProperty(window,"BASE_NAME",{
        value:"cyy",
        writable:false
    })
    window.a=1;
    console.log(window.a);

    可以使用Object.seal防止属性被扩展

    Object.defineProperty(window,"BASE_NAME",{
        value:"cyy",
        writable:false
    })
    Object.seal(BASE_NAME);//防止常量的属性被修改
    BASE_NAME.a=1;
    console.log(BASE_NAME);
    console.log(BASE_NAME.a);

    Object.seal能够防止属性被扩展,但是已经存在的属性,值是可以修改的

    var cyy={a:1};
    Object.seal(cyy);
    console.log(cyy);
    cyy.b=2;
    console.log(cyy);//不能扩展,没有b属性
    cyy.a=3;
    console.log(cyy);//属性能被修改,a被改变

    如果想要禁止属性被修改,还是使用Object.defineProperty

    var cyy={a:1};
    //禁止修改cyy对象的a属性
    Object.defineProperty(cyy,"a",{
        writable:false
    })
    Object.seal(cyy);
    console.log(cyy);
    cyy.a=3;
    console.log(cyy);//属性不能被修改

    也就是说,Object.defineProperty和Object.seal结合使用,可以达到Object.freeze的效果

    //在ES6之前,封装函数,使得常量不能被修改
    //引用类型的常量,属性也不能被修改和扩展
    Object.defineProperty(Object,"myfreeze",{
        value:function(obj){
            for(var i in obj){
                if(obj.hasOwnProperty(i)){
                    Object.defineProperty(obj,i,{
                        writable:false
                    })
                }
            }
            Object.seal(obj);
        }
    })
    
    const cyy={a:1};
    Object.myfreeze(cyy);

    补充:里面每一行undefined是console.log()执行之后的返回值。

    log()本质上是一个函数,函数中如果没有设置return返回值,默认返回undefined。

    这个不用管,不是代码的问题,忽略这个undefined,只看前面输出的内容即可

    hasOwnProperty 判断属性是原型上的属性,还是自身的属性

    var obj1={
        a:1,
        b:2
    }
    var obj2=Object.create(obj1);
    obj2.c=3;
    obj2.d=4;
    
    //for in遍历到了所有属性,有原型上的a和b属性,还有自身的c和d属性
    for(var i in obj2){
        console.log(obj2[i]);
    }
    
    //hasOwnProperty 只会显示自身的属性(不包括原型属性)
    for(var i in obj2){
        if(obj2.hasOwnProperty(i)){
            console.log(obj2[i]);        
        }
    }

    数组使用自定义的仿freeze方法

    //在ES6之前,封装函数,使得常量不能被修改
    //引用类型的常量,属性也不能被修改和扩展
    Object.defineProperty(Object,"myfreeze",{
        value:function(obj){
            for(var i in obj){
                if(obj.hasOwnProperty(i)){
                    Object.defineProperty(obj,i,{
                        writable:false
                    })
                }
            }
            Object.seal(obj);
        }
    })
    
    const cyy=[];
    Object.myfreeze(cyy);

    但是,如果对象的属性值又是一个对象的话,那这个对象的属性值还是可以被修改的

    //在ES6之前,封装函数,使得常量不能被修改
    //引用类型的常量,属性也不能被修改和扩展
    Object.defineProperty(Object,"myfreeze",{
        value:function(obj){
            for(var i in obj){
                if(obj.hasOwnProperty(i)){
                    Object.defineProperty(obj,i,{
                        writable:false
                    })
                }
            }
            Object.seal(obj);
        }
    })
    
    var cyy={
        name:"cyy",
        age:18,
        num:{
            a:1,
            b:2
        }
    }
    Object.myfreeze(cyy);

    需要使用递归来解决

    //在ES6之前,封装函数,使得常量不能被修改
    //引用类型的常量,属性也不能被修改和扩展
    Object.defineProperty(Object,"myfreeze",{
        value:function(obj){
            for(var i in obj){
                if(obj.hasOwnProperty(i)){
                    Object.defineProperty(obj,i,{
                        writable:false
                    })
                }
    
                //如果属性值是对象,则再次进行遍历
                if(obj[i] instanceof Object){
                    Object.myfreeze(obj[i]);
                }
            }
            Object.seal(obj);
        }
    })
    
    var cyy={
        name:"cyy",
        age:18,
        num:{
            a:1,
            b:2
        }
    }
    Object.myfreeze(cyy);

  • 相关阅读:
    CSS为英文和中文字体分别设置不同的字体
    进程控制之孤儿进程
    求解逻辑问题:谁养鱼
    2019-7-29-win10-uwp-如何使用DataTemplate
    2019-7-29-win10-uwp-如何使用DataTemplate
    2018-8-10-win10-uwp-修改Pivot-Header-颜色
    2018-8-10-win10-uwp-修改Pivot-Header-颜色
    2018-10-17-Sublime-Text-好用的插件
    2018-10-17-Sublime-Text-好用的插件
    2018-11-13-WPF-禁用实时触摸
  • 原文地址:https://www.cnblogs.com/chenyingying0/p/12559315.html
Copyright © 2011-2022 走看看