• 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);

  • 相关阅读:
    Java Web 网络留言板2 JDBC数据源 (连接池技术)
    Java Web 网络留言板3 CommonsDbUtils
    Java Web ConnectionPool (连接池技术)
    Java Web 网络留言板
    Java Web JDBC数据源
    Java Web CommonsUtils (数据库连接方法)
    Servlet 起源
    Hibernate EntityManager
    Hibernate Annotation (Hibernate 注解)
    wpf控件设计时支持(1)
  • 原文地址:https://www.cnblogs.com/chenyingying0/p/12559315.html
Copyright © 2020-2023  润新知