JavaScript 06-1——作用域和预解析

目录

1.作用域:

        (1)思维导图

1 - 作用域

1.1 作用域概述

1.2 全局作用域

1.3 局部作用域

1.4 JS没有块级作用域

2 - 变量的作用域

2.1 全局变量

2.2 局部变量

2.3 全局变量和局部变量的区别

3 - 作用域链

作用域案例

4 - 预解析

4.1 预解析的相关概念

4.2 变量预解析

4.3 函数预解析

4.4 函数表达式声明函数问题

作用域案例:


1.作用域:

        (1)思维导图

1 - 作用域

1.1 作用域概述

 通常来说,一段程序代码中所用到的名字并不总是有效和可用的,而限定这个名字的可用性的代码范围就是这个名字的作用域。作用域的使用提高了程序逻辑的局部性,增强了程序的可靠性,减少了名字冲突。
 ​
 JavaScript(es6前)中的作用域有两种:
  • 全局作用域

  • 局部作用域(函数作用域)

1.2 全局作用域

 作用于所有代码执行的环境(整个 script 标签内部)或者一个独立的 js 文件。

1.3 局部作用域

 作用于函数内的代码环境,就是局部作用域。 因为跟函数有关系,所以也称为函数作用域。

1.4 JS没有块级作用域

  • 块作用域由 { } 包括。

  • 在其他编程语言中(如 java、c#等),在 if 语句、循环语句中创建的变量,仅仅只能在本 if 语句、本循环语句中使用,如下面的Java代码:

    java有块级作用域:

     if(true){
       int num = 123;
       system.out.print(num);  // 123
     }
     system.out.print(num);    // 报错

    以上java代码会报错,是因为代码中 { } 即一块作用域,其中声明的变量 num,在 “{ }” 之外不能使用;

    而与之类似的JavaScript代码,则不会报错:

Js中没有块级作用域(在ES6之前)

 if(true){
   var num = 123;
   console.log(123); //123
 }
 console.log(123);   //123
    <script>
        // 1.JavaScript作用域 : 就是代码名字(变量)在某个范围内起作用和效果 目的是为了提高程序的可靠性更重要的是减少命名冲突
        // 2. js的作用域(es6)之前 : 全局作用域   局部作用域 
        // 3. 全局作用域: 整个script标签 或者是一个单独的js文件
        var num = 10;
        var num = 30;
        console.log(num);

        // 4. 局部作用域(函数作用域) 在函数内部就是局部作用域 这个代码的名字只在函数内部起效果和作用
        function fn() {
            // 局部作用域
            var num = 20;
            console.log(num);
        }
        fn();

2 - 变量的作用域

 在JavaScript中,根据作用域的不同,变量可以分为两种:
  • 全局变量

  • 局部变量

2.1 全局变量

 在全局作用域下声明的变量叫做全局变量(在函数外部定义的变量)。
  • 全局变量在代码的任何位置都可以使用

  • 在全局作用域下 var 声明的变量 是全局变量

  • 特殊情况下,在函数内不使用 var 声明的变量也是全局变量(不建议使用)

2.2 局部变量

 在局部作用域下声明的变量叫做局部变量(在函数内部定义的变量)
  • 局部变量只能在该函数内部使用

  • 在函数内部 var 声明的变量是局部变量

  • 函数的形参实际上就是局部变量

2.3 全局变量和局部变量的区别

  • 全局变量:在任何一个地方都可以使用,只有在浏览器关闭时才会被销毁,因此比较占内存

  • 局部变量:只在函数内部使用,当其所在的代码块被执行时,会被初始化;当代码块运行结束后,就会被销毁,因此更节省内存空间

 <script>
        // 变量的作用域: 根据作用域的不同我们变量分为全局变量和局部变量
        // 1. 全局变量: 在全局作用域下的变量 在全局下都可以使用
        // 注意 如果在函数内部 没有声明直接赋值的变量也属于全局变量
        var num = 10; // num就是一个全局变量
        console.log(num);

        function fn() {
            console.log(num);

        }
        fn();
        // console.log(aru);

        // 2. 局部变量   在局部作用域下的变量   后者在函数内部的变量就是 局部变量
        // 注意: 函数的形参也可以看做是局部变量
        function fun(aru) {
            var num1 = 10; // num1就是局部变量 只能在函数内部使用
            num2 = 20;
        }
        fun();
        // console.log(num1);
        // console.log(num2);
        // 3. 从执行效率来看全局变量和局部变量
        // (1) 全局变量只有浏览器关闭的时候才会销毁,比较占内存资源
        // (2) 局部变量 当我们程序执行完毕就会销毁, 比较节约内存资源
    </script>
    <script>
        // js中没有块级作用域  js的作用域: 全局作用域  局部作用域  现阶段我们js 没有 块级作用域
        // 我们js 也是在 es6 的时候新增的块级作用域
        // 块级作用域 {}   if {}  for {}
        // java 
        // if(xx) {
        //     int num = 10;
        // }
        // 外面的是不能调用num的
        if (3 < 5) {
            var num = 10;
        }
        console.log(num);
    </script>

3 - 作用域链

 只要是代码都一个作用域中,写在函数内部的局部作用域,未写在任何函数内部即在全局作用域中;如果函数中还有函数,那么在这个作用域中就又可以诞生一个作用域;根据在**[内部函数可以访问外部函数变量]**的这种机制,用链式查找决定哪些数据能被内部函数访问,就称作作用域链
 ​
 案例分析1:
 function f1() {
     var num = 123;
     function f2() {
         console.log( num );
     }
     f2();
 }
 var num = 456;
 f1();

 作用域链:采取就近原则的方式来查找变量最终的值。
 var a = 1;
 function fn1() {
     var a = 2;
     var b = '22';
     fn2();
     function fn2() {
         var a = 3;
         fn3();
         function fn3() {
             var a = 4;
             console.log(a); //a的值 ?
             console.log(b); //b的值 ?
         }
     }
 }
 fn1();

    <script>
        // 作用域链  : 内部函数访问外部函数的变量,采取的是链式查找的方式来决定取那个值 这种结构我们称为作用域链   就近原则
        var num = 10;

        function fn() { // 外部函数
            var num = 20;

            function fun() { // 内部函数
                console.log(num);

            }
            fun();
        }
        fn();
    </script>

作用域案例

 <script>
        // 案例1 : 结果是几?
        function f1() {
            var num = 123;

            function f2() {
                var num = 0;
                console.log(num); // 站在目标出发,一层一层的往外查找
            }
            f2();
        }
        var num = 456;
        f1();
        // 案例2 :结果是几?
        var a = 1;

        function fn1() {
            var a = 2;
            var b = '22';
            fn2();

            function fn2() {
                var a = 3;
                fn3();

                function fn3() {
                    var a = 4;
                    console.log(a); //a的值 ?
                    console.log(b); //b的值 ?
                }
            }
        }
        fn1();
    </script>

4 - 预解析

4.1 预解析的相关概念

 JavaScript 代码是由浏览器中的 JavaScript 解析器来执行的。JavaScript 解析器在运行 JavaScript 代码的时候分为两步:预解析和代码执行。
  • 预解析:在当前作用域下, JS 代码执行之前,浏览器会默认把带有 var 和 function 声明的变量在内存中进行提前声明或者定义。

  • 代码执行: 从上到下执行JS语句。

    预解析会把变量和函数的声明在代码执行之前执行完成。

4.2 变量预解析

 预解析也叫做变量、函数提升。
 变量提升(变量预解析): 变量的声明会被提升到当前作用域的最上面,变量的赋值不会提升。
 console.log(num);  // 结果是多少?
 var num = 10;      // ?
 结果:undefined
 ​
 注意:**变量提升只提升声明,不提升赋值**

4.3 函数预解析

 函数提升: 函数的声明会被提升到当前作用域的最上面,但是不会调用函数。
 fn();
 function fn() {
     console.log('打印');
 }
 结果:控制台打印字符串 --- ”打印“ 
 ​
 注意:函数声明代表函数整体,所以函数提升后,函数名代表整个函数,但是函数并没有被调用! 

4.4 函数表达式声明函数问题

 函数表达式创建函数,会执行变量提升,此时接收函数的变量名无法正确的调用:
 fn();
 var  fn = function() {
     console.log('想不到吧');
 }
 结果:报错提示 ”fn is not a function"
 ​
 解释:该段代码执行之前,会做变量声明提升,fn在提升之后的值是undefined;而fn调用是在fn被赋值为函数体之前,此时fn的值是undefined,所以无法正确调用
    <script>
        // 1问  
        console.log(num);

        // 2问
        console.log(num); // undefined  坑 1
        var num = 10;
        // 相当于执行了以下代码
        // var num;
        // console.log(num);
        // num = 10;

        // 3问  
        function fn() {
            console.log(11);
        }
        fn();

        // 4问
        fun(); // 报错  坑2 
        var fun = function() {
                console.log(22);

            }
            // 函数表达式 调用必须写在函数表达式的下面
            // 相当于执行了以下代码
            // var fun;
            // fun();
            // fun = function() {
            //         console.log(22);

        //     }

        // 1. 我们js引擎运行js 分为两步:  预解析  代码执行
        // (1). 预解析 js引擎会把js 里面所有的 var  还有 function 提升到当前作用域的最前面
        // (2). 代码执行  按照代码书写的顺序从上往下执行
        // 2. 预解析分为 变量预解析(变量提升) 和 函数预解析(函数提升)
        // (1) 变量提升 就是把所有的变量声明提升到当前的作用域最前面  不提升赋值操作
        // (2) 函数提升 就是把所有的函数声明提升到当前作用域的最前面  不调用函数
    </script>

作用域案例:

 <script>
        // 预解析案例
        // 案例1
        // var num = 10;
        // fun();

        // function fun() {
        //     console.log(num);
        //     var num = 20;
        // }
        // // 相当于执行了以下操作
        // // var num;

        // // function fun() {
        // //     var num;
        // //     console.log(num);
        // //     num = 20;
        // // }
        // // num = 10;
        // // fun();
        // // 案例2
        // var num = 10;

        // function fn() {
        //     console.log(num);
        //     var num = 20;
        //     console.log(num);
        // }
        // fn();
        // // 相当于以下代码
        // // var num;

        // // function fn() {
        // //     var num;
        // //     console.log(num);
        // //     num = 20;
        // //     console.log(num);
        // // }
        // // num = 10;
        // // fn();
        // // 案例3
        // var a = 18;
        // f1();

        // function f1() {
        //     var b = 9;
        //     console.log(a);
        //     console.log(b);
        //     var a = '123';
        // }
        // 相当于以下代码
        // var a;

        // function f1() {
        //     var b;
        //     var a;
        //     b = 9;
        //     console.log(a);
        //     console.log(b);
        //     a = '123';
        // }
        // a = 18;
        // f1();
        // 案例4
        f1();
        console.log(c);
        console.log(b);
        console.log(a);

        function f1() {
            var a = b = c = 9;
            console.log(a);
            console.log(b);
            console.log(c);
        }
        // 以下代码
        // function f1() {
        //     var a;
        //     a = b = c = 9;
        //     // 相当于 var  a  = 9; b = 9; c = 9; b 和 c 直接赋值 没有var 声明 当 全局变量看
        //     // 集体声明  var a = 9, b = 9, c = 9;
        //     console.log(a);
        //     console.log(b);
        //     console.log(c);
        // }
        // f1();
        // console.log(c);
        // console.log(b);
        // console.log(a);
    </script>

 笔记内容来源于哔哩哔哩pink老师javascript教程,思维导图是自己整理的

猜你喜欢

转载自blog.csdn.net/weixin_51081257/article/details/121406797