• JS 全局作用域和局部作用域


    一、作用域

    1、什么是作用域(Scope)

     通常来说,一段程序代码中所用到的名字不总是有效和可用的,而限定这个名字的可用性的代码范围就是这个名字的作用域。

    JS作用域就是代码名字(变量)作用的范围

    作用域的目的:是为了提高程序的可靠性,更重要的是减少命名冲突

    2、JS的作用域的分类(ES6之前)

    JS作用域可以分为两大类:全局作用域 、局部作用域(函数作用域)

    (一)全局作用域:

      直接编写在 script 标签之中的JS代码,都是全局作用域;

      或者是一个单独的 JS 文件中的。

      全局作用域在页面打开时创建,页面关闭时销毁;

      在全局作用域中有一个全局对象 window(代表的是一个浏览器的窗口,由浏览器创建),可以直接使用。

    在全局作用域中,

    • 所有创建的变量都会作为 window 对象的属性保存。

    • 所有创建的函数都会作为 window 对象的方法保存。

     

    (二)局部作用域(函数作用域):

      在函数内部就是局部作用域,这个代码的名字只在函数的内部起作用

      调用函数时创建函数作用域,函数执行完毕之后,函数作用域销毁;

      每调用一次函数就会创建一个新的函数作用域,它们之间是相互独立的。

    实例分析:

    在这个例子里面 un函数里面的 局部作用域中 有一个 num 变量,script 标签的全局作用域中也有一个 num变量。

    (一个在全局作用域下,另一个在局部作用域下,虽然两个变量的变量名相冲突,但是并没有影响。)

    所以,在不同的作用域下,变量名相同也不受影响,这样就很有效的减少了命名冲突。

    <script>
        var num = 10;
        function nu(){
            var num = 20;
            console.log(num);
        }
        nu();
        console.log(num);
    </script>

     JS现阶段(ES6之前)没有块级作用域,被块级作用域就是用大括号({})包含的就是块级作用域。

    二、变量的作用域

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

    (一)全局变量

      1、在全局作用域下声明的变量叫做 全局变量在函数外部定义的变量

      2、全局变量在全局(代码的任何位置)下都可以使用;全局作用域中无法访问到局部作用域中的变量。

      3、全局变量第一种创建方式:在全局作用域下 var声明的变量是全局变量

      4、全局变量第二种创建方式:如果在函数内部,没有使用 var关键字声明直接赋值的变量也属于 全局变量。(不建议使用)

    (变量 num 直接写在 script标签下,所以 num是全局变量。)

    <script>
    var num = 10;
        function nu(){
            console.log(num);
        }
    nu(); console.log(num);
    </script>

     (二)局部变量:

      1、在局部作用域下声明的变量叫做局部变量在函数内部定义的变量

      2、局部变量只能在函数内部使用,在局部作用域中可以访问到全局变量。

      3、在函数内部 var 声明的变量就是局部变量

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

    <script>
        function nu(){
            var num1 = 10;
            num2 = 20;
            console.log(num1);
        }
        nu();
        console.log(num2);
    </script>

    (三)全局变量和局部变量的区别:

    全局变量在任何一个地方都可以使用,全局变量只有在浏览器关闭的时候才会销毁,比较占用内存资源

    局部变量只能在函数内部使用,当其所在代码块被执行时,会被初始化;当代码块执行完毕就会销毁,因此更节省节约内存空间;

     

    三、变量的声明提前和函数的声明提前

    (一) 变量的声明提前

    使用 var 关键字声明的变量,会在所有的代码执行之前被声明。(但是不会赋值)

    全局变量即使是写在最下面,也相当于在所有代码之前的最上面声明的变量。

      等价于 

     (在这个例子中最终结果返回的是 undefined,这是因为 变量a 就相当于在所有代码最上面被声明,但下面才被赋值,所以结果是 undefined未定义)

    如果声明变量的时候不使用 var 关键字,那么变量就不会被声明提前。

     

    (如果不写 var 关键字,变量声明就无法提前,所以在 console.log前面就找不到 变量,所以返回结果报错)

    (二) 函数的声明提前

    使用函数声明形式创建的函数function 函数名() {};

    它会在所有代码执行之前就被创建。所以可以在函数声明之前被调用

     等价于

    使用函数表达式创建的函数var 变量名 = function(){};

    不会被声明提前,所以不能再声明前调用。

     

    四、作用域链

    只要是代码,就有一个作用域,写在函数内部的就叫做局部作用域;

    如果函数中还有函数,那么在这个作用域中又可以诞生一个作用域;

    当在函数作用域中操作一个变量的时候,会先在自身作用域中查找,如果有就直接使用,如果没有就向上级作用域中寻找。如果全局作用域中也没有,那么就报错。

    根据内部函数可以访问可以访问外部函数变量的这种机制,用链式查找决定哪些数据能被内部函数访问,就称为函数作用域链

    作用域链:内部函数访问外部函数的变量,采取的是链式查找的方法来决定取那个结构,这种结构称之为作用域链

    作用域链的原则:就近原则

    (作用域链采用链式查找的方式,一层一层向上查找,先查找外面的嵌套的函数是否有所需内容,找到就输出相应的结果,如果没有再向上查找。就近原则

    实例一:


     下面代码最终输出的结果是多少?

     思路分析:

     按照链式查找先到上一级查找,输出内容在2级链,向上到 1级链去查找,如果 1级链也没有就继续向上查找。如果都找不到就会返回 undefined(未定义)。

    因为1级链中有 unm 值,所以输出num结果就是 123。

    实例二:


     下面代码最终输出的结果?

    注意:在更长的结构中画图分析太过于麻烦,可以从输出目标console.log(); 位置向外层的结构看,寻找最近的变量

    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);  //求 a的值
                    console.log('b= ' + b);  //求 b的值
                }
            }
        }
        fn1();

    最终结果是:

  • 相关阅读:
    CSS实现点击改变元素背景色
    php三种方法从控制结构或脚本中跳出
    如何关闭运行在某端口的的进程,例如 :8080端口
    Webpack简易入门教程
    git add -A 和 git add . 的区别
    怎样把已经做好的网页传到网上去?
    jquery源码之事件系统-- jQuery.event
    jquery源码之缓存系统--$.data
    jquery源码之延迟对象--Deferred
    jquery源码之低调的回调函数队列--Callbacks
  • 原文地址:https://www.cnblogs.com/nyw1983/p/11992930.html
走看看 - 开发者的网上家园