闭包

作者: 未路过 | 来源:发表于2022-08-25 22:28 被阅读0次

    从广义的角度来说:JavaScript中的函数都是闭包;
    从狭义的角度来说:JavaScript中一个函数,如果访问了外层作用域的变量,那么它是一个闭包; 闭包由两部分组成:函数+可以访问的自由变量 按道理说,foo执行完之后,它的ao对象应该也就销毁了,但是因为闭包,它没有被销毁

    1.普通函数执行

    var message = 'hello';
    function foo(){
      var name = 'foo';
      var age = 18;
    }
    
    function test(){
      console.log('test');
    }
    
    foo();
    test();
    

    1.在执行所有代码之前,引擎会在内存里创建GO对象(ox100),它里面有String对象啦,window对象这些 对象。是被提前创建好的。然后现在去执行代码, GO对象是不会被销毁的
    2.创建执行上下文栈
    3.然后执行全局代码,创建全局执行上下文,然后创建全局执行上下文的VO,这个Vo指向GO。
    4.然后,这个时候解析全局代码,往全局GO里面加东西了,原来的全局里面有Date,window,String等等,加入
    message(undefined)foo(oxa00),test(oxboo)等变量。解析foo是函数,就创建一个函数对象 foo(oxa00),里面有函数的父级作用域,也就是全局的GO对象(ox100)。,还有函数执行体(函数代 码)。 解析test是函数,就创建一个函数对象test(oxb00),里面有函数的父级作用域,也就是全局的GO对象 (ox100)。,还有函数执行体(函数代码)

    24.PNG

    5 接下来执行执行代码,先给message赋值,变成了hello,然后执行函数foo。

    6 创建foo函数的函数执行上下文。往里面创建VO对象,VO指向AO对象。创建一个foo函数的AO对象(ox200)。

    默认里面没有对象,然后解析函数,里面放入name:undefined,age:undefined

    image.png

    7.然后执行一行一行执行foo里面的代码,同时把AO里面的name赋值'foo',age赋值18;


    image.png

    8.foo函数执行完之后,栈里面的foo函数执行上下文就会被销毁,一旦销毁,对foo的AO对象的引用将会没有,然后oxaoo就会被销毁。

    image.png

    一般情况下,在函数执行上下文被销毁的同时,函数的AO对象也会被销毁

    9.test函数执行完之后也是一样,test的AO对象也会被销毁。代码执行完之后的内存结果就是上图。

    2.闭包函数执行

    var message = 'hello'
    function foo(){
      var name = 'foo';
      var age = 18;
    
      function bar(){
        console.log(name);
        console.log(age);
      }
    
      return bar
    }
    
    
    var fn = foo();
    fn()
    

    执行完var fn = foo();之后

    image.png

    然后foo的执行上下文被销毁,但是bar不会被销毁,因为fn指着它。 然后bar对象不会被销毁,它上面的foo的ao对象也不会被销毁的。因为bar里面有parentScope这个东西,它指向foo的AO对象。


    image.png

    接下来执行fn()


    image.png

    然后销毁fn的执行上下文.


    image.png

    foo的AO对象是没有被销毁的,因为bar的父级作用域是指向foo的AO的。 内存泄漏:这里的bar函数对象一直不会被销毁,也就是foo的AO也一直不会被销毁。 如果执行完一次fn之后,就再也不会执行这个fn了,那么保存的bar和foo的AO也就没有意义了。 该销毁的东西没有被销毁,就是内存泄漏。 fn= null;就可以解决


    image.png

    虽然这时候bar和foo的AO循环引用,但是根据标记清除法,只要从根对象OG开始能找到的对象就不会被销毁。

    但是bar和foo的AO从根对象指不向他们,他们就会被销毁。


    image.png

    如果也想销毁掉foo这个函数,也是一样,直接foo = null;就可以了;

    image.png

    3. 内存泄漏

    image.png image.png
    
    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <meta http-equiv="X-UA-Compatible" content="IE=edge">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>Document</title>
    </head>
    <body>
      
    </body>
    <script>
      // var arr = new Array(1024 * 1024).fill(1)
      // console.log(arr);
       //整数占据四个字节 4Byte  1MB=1024KB
       //1024*1024*4 = 1024 * 1Kb * 4B = 4kB * 1024 = 4MB
       //现在这个数组占据的空间是4MB
    
       function createFnArray(){
        var arr = new Array(1024 * 1024).fill(1);
    
        return function(){
          console.log(arr.length);
        }
       }
       var arrayFns = [];
    
       for(var i = 0; i < 100; i++){
        
        //调用100次createFnArray(),就会有100个createFnArray对应的AO。
        //返回100个函数对象,每一个函数对象都会引用createFnArray对应的AO。
        arrayFns.push(createFnArray());
       }
    </script>
    </html>
    

    4.闭包中没有被使用的属性

       function foo(){
         var name = 'why';
         var age = 18;
    
        function bar(){
            debugger
          console.log(name);
        }
        return bar
       }
    
       var fn = foo();
       fn();
    

    foo的AO对象不会被销毁,里面有name和age两个变量,name因为被bar引用,不会被销毁,但是从引擎优化的角度,发现这里age根本不会被用到,依然保留age的话,会占用内存空间,影响内存性能。一般情况下,js引擎会把多余的属性销毁掉。

    5.对象中的函数

    var test = "test"
     var p1 = {
       p1eating(){
        // console.log(test);
        var p1test = "p1test"
         var p2 = {
           p2eating(){
             var p2test = "p2test"
             var p3 = {
               p3eating(){
                 //console.log(test);
                 console.log(p1test);
                 //console.log(p2test);
               }
               
             }
             p3.p3eating()
           }
         }
         p2.p2eating()
       }
       
     }
    
     p1.p1eating()
    

    对象中的函数也是存在闭包的,方法中的变量也是向上层作用域中去找的,而且对象不是一个作用域,对象中的方法和全局才是

    相关文章

      网友评论

          本文标题:闭包

          本文链接:https://www.haomeiwen.com/subject/szizgrtx.html