• 第十一节:ES6解构赋值、var/let/const详解(作用域提升、windows关系、暂时性死区、使用场景等)


    一. ES6解构赋值

    1. 含义

     允许按照一定模式,从数组和对象中提取值,对变量进行赋值的过程,叫做解构

    2. 套路

          (1). 符号:[]

          (2). 别名:xx:别名

          (3). 默认值: xx='默认值'  或 xx:别名='默认值'

          (4). 剩余参数: ...xxx, 对象解构中是对象,数组解构中是数组

    3. 数组的解构

     全部解构、解构某个元素、剩余参数的使用、解构+默认值

    代码分享:
    {
      let nameArrays = ["ypf1", "ypf2", "ypf3"];
      //全部解构
      let [name1, name2, name3] = nameArrays;
      console.log(name1, name2, name3); //ypf1 ypf2 ypf3
      //解构某一个元素
      let [, , myName3] = nameArrays; //ypf3
      console.log(myName3);
      //解构出来一个元素,剩下的放到数组里(形如剩余参数)
      let [item1, ...itemList] = nameArrays;
      console.log(item1, itemList); //ypf1 [ 'ypf2', 'ypf3' ]
      //解构的同时赋默认值
      let [l1, l2, l3, l4 = "ypf4"] = nameArrays;
      console.log(l1, l2, l3, l4); //ypf1 ypf2 ypf3 ypf4
    }

    4. 对象的解构

     全部解构、解构起别名、结构+默认值、解构+别名+默认值、剩余参数、复杂对象解构、函数中使用。

    代码分享:

    {
        let obj = {
            name: "ypf",
            age: 18,
            height: 1.82,
        };
        // 解构
        let { name, age, height } = obj;
        console.log(name, age, height);
    
        // 解构并起别名
        let { name: name1, age: age1, height: height1 } = obj;
        console.log(name1, age1, height1);
    
        // 解构+默认值,解构+别名+默认值
        let { name2 = "ypf2", name: name3 = "ypf3" } = obj;
        console.log(name2, name3); //ypf2 ypf
    
        // rest剩余参数的使用
        let { name: name4, ...restObj } = obj;
        console.log(name, restObj); //ypf { age: 18, height: 1.82 }
    
        // 复杂对象的解构
        let options = {
            size: {
                 100,
                myheight: 200,
            },
            items: ["Cake", "Donut"],
            extra: true, // something extra that we will not destruct
        };
        let {
            size: { width, myheight },
            items: [item1, item2], // assign items here
            title = "Menu", // not present in the object (default value is used)
        } = options;
    
        console.log(title); // Menu
        console.log(width); // 100
        console.log(myheight); // 200
        console.log(item1); // Cake
        console.log(item2); // Donut
    
        //函数中使用
        function foo({ name, age }) {
            console.log(name, age);
        }
        foo(obj); //ypf 18
    }
    View Code

    5. 字符串的解构

     和数组解构类似

     代码分享:

    {
      let str = "ypf001";
      let [a, b, c, d, e] = str;
      console.log(a, b, c, d, e); //y p f 0 0
    }

    二. var/let/const详解

    1. let 基本使用

    (1). let 不允许声明同名变量(var可以)

    (2). 其它声明变量方面和var没有太大区别

    代码分享:

        // 1.1 let 不允许声明同名变量 (下面代码报错)
        {
            let msg1 = "ypf1";
            let msg1 = "ypf2";
        }
        //1.2 var可以
        {
            var msg2 = "ypf1";
            var msg2 = "ypf2";
        }

    2. const基本使用

    (1).const不允许声明重复变量

    (2).const用来声明常量,保存的数据一旦被赋值,就不能被修改

     特别注意:对于number、string、bool等数值类型不能直接修改,但是如果赋值的是引用类型,那么可以通过引用找到对应的对象,修改对象的内容。

    【基本数据类型存储在 栈内存 中,引用数据类型存储在 堆内存 中然后在栈内存中保存 引用地址,对于引用类型而言,const 实际上保证的并不是变量的值不得改动,而是变量指向的那个内存地址所保存的数据不得改动。】

    (3). const声明变量的同时,必须赋值。

    代码分享:

    {
        //2.1 const不允许声明同名变量(下面代码报错)
        {
            const msg1 = "ypf1";
            const msg1 = "ypf2";
        }
        // 2.2 声明的常量,对于基本数据类型不允许修改(下面代码报错)
        {
            const name1 = "ypf1";
            name1 = "ypf2";
            console.log(name1); //报错 Assignment to constant variable.
        }
        // 2.3 声明的常量,如果是引用类型,修改引用类型的地址,不允许;但是修改引用类型的值,是可以的
        {
            const obj = {
                name: "ypf1",
                age: 20,
            };
            obj.age = "30"; // 允许的,改的堆内存中的值,栈中的存放的地址没有修改
            console.log(obj.age);
            obj = {
                name: "ypf2",
            }; // 不允许修改栈内存中存放的引用地址!! Assignment to constant variable.
        }
        //2.4 声明变量的同时必须赋值
        {
            //   const msg;  //必须初始化 "const" 声明
        }
    }

    3. var、let/const到底有没有作用域提升呢?(也叫变量提升)

    (1). 什么是作用域提升?

    【答:在声明变量的作用域中,如果这个变量可以在声明之前被访问,那么我们可以称之为作用域提升】

    (2). var是具有作用域提升的,如下例子,输出undefined,并没有报错,说明能访问。

    (3). let、const没有进行作用域提升,但是会在“解析阶段”被创建出来

    代码分享:

    {
        // 3.1 var是具有作用域提升的
        {
            console.log(a); //undefined
            var a = "ypf";
        }
        // 3.2 let/const创建的变量不能提前访问,所以不具有作用域提升功能
        {
            console.log(msg1); //Cannot access 'msg1' before initialization
            let msg1 = "ypf";
            console.log(msg2); //Cannot access 'msg2' before initialization
            const msg2 = "ypf";
        }
    } 

    4. var、let/const和windows的关系 (需要在index.html页面测试)

    (1). 全局通过var来声明一个变量,事实上会在window上添加一个属性

    (2). let、const是不会给window上添加任何属性的

    代码分享: 

        // 4.1 全局通过var来声明一个变量,事实上会在window上添加一个属性
        {
            var msg1 = "ypf1";
            console.log(window.msg1); //ypf1
        }
        // 4.2 let/const不会给window上添加任何属性的
        {
            let msg2 = "ypf2";
            let msg3 = "ypf3";
            console.log(window.msg2); //undefined
            console.log(window.msg3); //undefined
        }

    5. 块级作用域

    (1). 在之前的ES5中,没有块级作用域,只有函数作用域和全局作用域

    (2). var 没有块级作用域,let/const/function/class声明的类型都是具有块级作用域的

    注:不同的浏览器有不同实现的(大部分浏览器为了兼容以前的代码, 让function是没有块级作用域)

    (3). if/switch/for 都是具有块级作用域的

    (4). 块级作用域应用场景

          有多个按钮,想给每个按钮添加一个事件,然后点击按钮依次输出每个按你对应的顺序,想要的结果是 0,1,2,3  如果直接用for循环+var,输出的结果永远是最大值,因为var是全局变量   这里引入两种解决方案,闭包和let块级作用域

    代码分享: 

    {
        // 5.4 if/switch/for 对应的块级作用域分析
        // if
        {
            if (true) {
                var msg1 = "ypf1";
                let msg2 = "ypf2";
                const msg3 = "ypf3";
            }
            console.log(msg1); //ypf1
            console.log(msg2); //ReferenceError: msg2 is not defined
            console.log(msg3); //ReferenceError: msg3 is not defined
        }
        // switch
        {
            var color = "red";
            switch (color) {
                case "red":
                    var foo = "foo";
                    let bar = "bar";
            }
            console.log(foo); //foo
            console.log(bar); //bar is not defined
        }
        // for(重点!!)
        {
            for (var i = 0; i < 3; i++) {
                console.log("循环内:" + i); // 0、1、2
            }
            console.log("循环外:" + i); // 3
    
            for (let i = 0; i < 3; i++) {
                console.log("循环内:" + i); // 0、1、2
            }
            console.log("循环外:" + i); // ReferenceError: i is not defined
        }
    }
    
    // 块级作用域应用场景
    {
        const btns = document.getElementsByTagName("button");
    
        // 仔细理解!!!!
        // 参考博客:https://www.cnblogs.com/yaopengfei/p/14456993.html
        for (var i = 0; i < btns.length; i++) {
            btns[i].onclick = function () {
                console.log("第" + i + "个按钮被点击");
            };
        }
    
        // 方案1:采用闭包的方式解决
        for (var i = 0; i < btns.length; i++) {
            (function (n) {
                btns[i].onclick = function () {
                    console.log("第" + n + "个按钮被点击");
                };
            })(i);
        }
    
        // 方案2:直接使用let即可
        for (let i = 0; i < btns.length; i++) {
            btns[i].onclick = function () {
                console.log("第" + i + "个按钮被点击");
            };
        }
    }
    View Code

    6. let/const具有暂时性死区

    (1). 什么是暂时性死区?

       【答:只要块级作用域内存在 let 命令,它所声明的变量就绑定在了这个区域,不再受外部的影响。】

    (2). 案例如下

    {
        var a = 5;
        if (true) {
            a = 6;
            let a;
        }
        // Uncaught ReferenceError: Cannot access 'a' before initialization
    }

    7. 补充

        for (let i = 0; i < names.length; i++) 中不可以使用const声明变量

        for (const item of names)  中可以使用const声明变量

    8. 总结

    (1). 对于var的使用:

        我们需要明白一个事实,var所表现出来的特殊性:比如作用域提升、window全局对象、没有块级作用域等都是一些历史遗留问题;

        其实是JavaScript在设计之初的一种语言缺陷;

        但是在实际工作中,我们可以使用最新的规范来编写,也就是不再使用var来定义变量了;

    (2). 对于let、const:

        对于let和const来说,是目前开发中推荐使用的;

        我们会有限推荐使用const,这样可以保证数据的安全性不会被随意的篡改;

        只有当我们明确知道一个变量后续会需要被重新赋值时,这个时候再使用let;

        这种在很多其他语言里面也都是一种约定俗成的规范,尽量我们也遵守这种规范;

     

     

     

    !

    • 作       者 : Yaopengfei(姚鹏飞)
    • 博客地址 : http://www.cnblogs.com/yaopengfei/
    • 声     明1 : 如有错误,欢迎讨论,请勿谩骂^_^。
    • 声     明2 : 原创博客请在转载时保留原文链接或在文章开头加上本人博客地址,否则保留追究法律责任的权利。
     
  • 相关阅读:
    npm的使用
    js 数组去重
    js实现对象或者数组深拷贝
    js简单排序
    js判断类型
    鼠标移入移出事件
    jq中的attr和prop属性
    移动端底部被输入法顶起的解决办法
    vue中的number
    javascript要点(上)
  • 原文地址:https://www.cnblogs.com/yaopengfei/p/16002663.html
Copyright © 2020-2023  润新知