Bootstrap

【Javascript Day8】计算机存储方式、方法定义方式、作用域、预解析、对象

目录

计算机存储方式

方法的定义方式

声明式方法

表达式方式方法

作用域

变量作用域对代码影响

  1. 全局变量和局部变量重名

 2. 方法内不使用 var 定义变量对全局变量的影响

 3. 变量名和参数名重复

4. 作用域链 :作用域嵌套产生的作用域父子子孙关系

5. 嵌套作用域的变量相互访问

js预解析

1. var变量的变量提升

2. 声明式函数提升

3. 表达式函数提升

对象


计算机存储方式


// 计算机的软件运行时的内存使用而言,数据的存储方式主要分为两种存储区域
        //      栈空间:栈空间的存储容量受限 => 读取和查找变量的速度会更快
        //      堆空间:堆空间理论上容器是无限 => 存储更多数据

        // 数据的存储方式
        //  1. 基本类型:Number String Boolean null undefined
        //  2. 引用数据类型(复杂数据类型):Array

        // 变量名会被直接记录在 栈空间中,方便程序运行时的快速加载
        //      变量值的存储会因为类型不同存储区域不同
        //          1. 基本类型:值直接存在栈中,和变量名在一起
        //          2. 引用类型:存在堆中,通过内存地址编码进行关联,栈中的变量绑定时堆中的地址

        var num = 100; // 定义一个变量num 值为 100
        var num1 = num; // 定义一个变量 num1 值从 num 变量获取 => 100
        console.log(num,num1);
        
        num1 = 200; // 对变量 num1 进行重新赋值,取值200
        console.log(num,num1);

        // 因为 = 赋值运算只操作栈
        var arr = [1,2,3,4,5]; // 定义一个变量 arr ,值为 [1,2,3,4,5]
        var arr1 = arr; //定义一个变量 arr1, 值从 arr 变量获取 => [1,2,3,4,5]
        console.log(arr,arr1);
        
        arr1[0] = 999;
        console.log(arr,arr1); // [999,……] [999,……]

        arr1 = ["a","b","c"]; // 重新赋值一个全新的数据,所有堆提供一个新的地址
        console.log(arr,arr1);
        

        // 数据不同存储方式对方法参数的影响


//     方法参数传递会因为数据类型不同,分为 值传递 和 引用传递
        //          1. 值传递:将基本数据类型数据作为参数传递
        //          2. 引用传递:将引用数据类型的堆地址作为参数进行传递
        function printParams(a,b){
            a = "新数据";
            b[0] = 999;
            // 重新给b赋值了一个堆的指向数组地址,此时的b和传递的arr之间没有关系了
            b = [66,77,88];
            b[0] = 1111;
        }

        var str = "abc";
        var arr = [11,22,33]

        console.log(str,arr); // abc [11,22,33]
        
        // str 传递的是值 ,内部的修改不会影响到 str 变量本身  => 值传递
        // arr 传递的是地址 ,内部在不修改地址的情况下会影响的 arr 变量本身 => 引用传递
        printParams( str,arr )

        console.log(str,arr); // abc  [999,22,33]

方法的定义方式

声明式方法

   function show(){

        }

表达式方式方法

        //   => 以变量的规则声明
        var printFun = function(a,b){
            return a + b;
        }

        var res = printFun("a",123);

        console.log(res);

作用域

// 作用域:代码对变量或方法使用范围的一种限制
        //        让数据不会变成 脏数据

        // js作用域
        //     1. 全局作用域:同一个HTML加载的JS代码都可以直接访问的作用域
        //                  全局作用域声明的变量或者方法,在当前html的任何JS位置中都可以直接被访问
        //                  浏览器全局作用域实际上就是,JS提供窗口数据 window
        //                  浏览器加载JS时就会初始化变量值,当浏览器关闭时才会删除
        //     2. 局部作用域:声明的方法的方法体
        //                  每个方法的方法体范围就是一个局部作用域
        //                  局部作用域声明的变量或方法只能在当前作用域中使用
        //                  局部变量只有在方法被执行时才会初始化变量值,当方法执行完成后会进行删除

        // 全局变量声明 => 数据存在window上
        var people = "abc";
        var num = 100;

        console.log(window);
        // 直接使用全局变量名
        console.log("同script",num);
        // 通过  window.变量名  进行使用
        console.log("同script",window.num);

        
        // 局部作用
        function funA(){
            var count = 10;
            return count;
        }

        // 把方法返回的结果,重新定义成一个全局变量
        var a = funA();

        // 受作用域限制,方法外无法直接调用方法内的变量
        console.log(count);
        
        // console.log(a);


变量作用域对代码影响

  1. 全局变量和局部变量重名

       var msg = "全局msg";

        function printFunA(){
            console.log(msg);
        }
        printFunA(); // 输出:全局作用域变量msg

        // 就近原则
        function printFunB(){
            var msg = "局部msg";
            // 方法内无法获取全局变量msg
            console.log(msg); // 获取局部变量msg
        }
        printFunB(); // 输出:局部作用域变量msg
        console.log(msg); // 输出:全局作用域变量msg

 2. 方法内不使用 var 定义变量对全局变量的影响


        //      JS 变量定义时,只有具有声明符号 var 的变量表示为重新定义
        //                   如果变量定义时,没有使用 var ,会首先查询是否存在该变量:
        //                         如果存在直接使用,不存重新定义
        //                         如果不存在,重新定义全局变量
        var info = "全局info";
        function printFunC(){
            info = "局部info"; // 对全局变量 info 进行覆盖
            console.log(info);
        }
        printFunC(); // 输出:局部变量info
        console.log(info); // 输出:局部变量info
        
        function printFunD(){
            text = "局部text";
            console.log(text);
        }
        printFunD(); // 输出:局部text
        console.log(text); // 输出:局部text
        

 3. 变量名和参数名重复


        var num = 1000;
        function printFunE(num){
            // 方法形参是存在一个 隐藏的 var 关键字,所以形参是新变量定义,形参变量属于局部作用域
            console.log(num);
            num = 999;
            console.log(num);
        }
        printFunE(); // 输出:undefined , 999
        console.log(num); // 输出:1000 
        

4. 作用域链 :作用域嵌套产生的作用域父子子孙关系


        var flag = false;
        function printFunF(){

            // 局部方法
            // function printFunG(){
            //     console.log(flag);
            // }
            var printFunG = function(){
                console.log(flag); // 查找到了全局的 flag
            }
            printFunG(); // 输出:false

        }
        printFunF(); // 输出:没有任何输出
        // printFunG(); // 输出:报错 => 全局没有该方法

        var name = "张三";
        function printFunH(){
            var name = "李四";
            function printFunI(){
                console.log(name);
            }
            printFunI(); // 输出:李四
        }
        printFunH();


5. 嵌套作用域的变量相互访问


        function printFunJ(){
            var argA = "printFunJ-argA-变量";

            function printFunK(){
                var argB = "printFunK-argB-变量"
                console.log(argA);
            }
            printFunK();  // 输出:printFunJ-argA-变量

            console.log(argB); // 输出: 报错
        }
        printFunJ();

js预解析

// 预解析:浏览器先完成JS加载,加载完成后会进行运行
        //       加载的过程中,JS解析器会对一些特殊结构代码进行调整,保证浏览器正常运行

1. var变量的变量提升


        // console.log(msg); // 报错 ReferenceError: msg is not defined
        
        // 被提升的info
        // var info;
        console.log(info); // undefined => 触发预解析              //16行

        var info = "测试数据";                                //18行
        // 预解析 发现 16 使用了 18 的变量 
        // 将18行的变量拆分成两部分:var info;   info="测试数据";
        // 将声明提升到 16 之前定义;
        // info = "测试数据"; // 拆分后的赋值
        
        
        function showFun(){
            // 变量提升也受 作用域限制
            console.log(text);
            var text = "text变量";
        }
        showFun();
        // console.log(text);
        

2. 声明式函数提升


        //         声明式函数是一个整体语法,不能拆分的

        // testFun(); // ReferenceError: testFun is not defined

        printFunA();                                     39行
        // 因为是声明式函数,代码解析式,发现39需要调用41行代码,41行的方法代码会被整体提前
        function printFunA(){                      
            console.log("printFunA方法");
        }

3. 表达式函数提升


        printFunB(); // TypeError: printFunB is not a function
        // 代码解析式,发现47需要调用49行代码,
        // 49行被分解成   var printFunB;   printFunB = function(){……}
        // var printFunB 被提升到47行之前
        // 提升后的变量没有被赋值,默认值是undefined,不是一个方法,不能被()调用,所以47行报错
        var printFunB = function(){
            console.log("printFunB方法");
        }

对象

// 对象:是一组无序的相关属性和方法的集合
        //      是一种代码中定义的数据格式,用于统一记录物品或者事物的相关信息
        
        // var car = ["发动机","车架","轮子"];
        // console.log( car[1] );

        // 字面量对象定义:
        /*
            key 自定义对象属性名称 = 变量声明
            value 属性的取值 = 变量赋值            var 对象名 = { 
                key:value,
                key1:value1,
                ……
            };
        */
       

 var car = {
            motor:"四缸发动机",
            frame:"铝合金",
            seat:"真皮"
        };

        // 对象的取值  对象变量名称.对象属性名
        console.log( car.motor );
        
        var stu = {
            no:10001,
            name:"tom",
            age:23,
            sex:"男"
        }

        console.log( stu.name );
        console.log( stu.age );
        console.log( stu.sex );

        var songList = [
            // 存储很多歌曲
            {
                img:"http://p1.music.126.net/WCE6Za49yYQyDvnNJykJ-w==/109951170209787177.jpg?param=140y140",
                count:4399,
                name:"我的歌声1",
                singer:"张三1"
            },
            {
                img:"http://p1.music.126.net/WCE6Za49yYQyDvnNJykJ-w==/109951170209787177.jpg?param=140y140",
                count:3000,
                name:"我的歌声2",
                singer:"张三2"
            },
            {
                img:"http://p1.music.126.net/WCE6Za49yYQyDvnNJykJ-w==/109951170209787177.jpg?param=140y140",
                count:200,
                name:"我的歌声3",
                singer:"张三3"
            },
            {
                img:"http://p1.music.126.net/WCE6Za49yYQyDvnNJykJ-w==/109951170209787177.jpg?param=140y140",
                count:6666666,
                name:"我的歌声4",
                singer:"张三4"
            },
            {
                img:"http://p1.music.126.net/WCE6Za49yYQyDvnNJykJ-w==/109951170209787177.jpg?param=140y140",
                count:200,
                name:"我的歌声3",
                singer:"张三3"
            },
            {
                img:"http://p1.music.126.net/WCE6Za49yYQyDvnNJykJ-w==/109951170209787177.jpg?param=140y140",
                count:666,
                name:"我的歌声4",
                singer:"张三4"
            }

        ];

        // console.log( songList[1].name );
        
        for (var i = 0; i < songList.length; i++) {
            // console.log( songList[i] );
            // console.log( songList[i].img );
            document.write("<div class='box'>")
            document.write(`<img src="${songList[i].img}">`)
            // console.log( songList[i].count );
            var num = parseInt( songList[i].count/10000);
            var temp = num>1 ? num+"万":songList[i].count

            document.write(`<div>播放量:${ temp  }</div>`)
            // console.log( songList[i].name );
            document.write(`<div>名字:${songList[i].name}</div>`)
            // console.log( songList[i].singer );
            document.write(`<div>演唱者:${songList[i].singer}</div>`)
            document.write("</div>")
        }

;