原生JS的闭包详解~~


了解闭包之前我们需要懂的东西:需要知道JS的作用域链以及预解析。

      进入话题,作用域链上面的东西是存在哪里的呢。 是一个栈结构,最底层是window对象。

栈就是类似一个桶装结构,如图1:                               

                                            图一 :    栈结构具有的特点就是先入后出。 好比你放进桶里的东西,你需要从最上面开始拿出来。

JS代码的解析过程中:例如JS代码里有一个函数foo.

                                                              <script>

                   var a = 1;

                                                                  function foo()

                                                                  { }

                    foo();

                                                             </script>

预解析:那么预解析到这个函数时,发生了如下的事情:   由于函数是引用类型的对象,实际数据存在堆里,那么在栈里只存放了地址。0x1101这个地址指向堆的实际数据。

运行到这个函数时,它会创建一个foo的作用域链对象。然后存入一个栈里,这个栈底层永远是window.

 

函数执行=>foo() 又会发生的事情:栈里面的foo创建了一个活动对象。即执行了这个函数。

                                             

 

当函数执行完毕:foo的作用域链出栈,没有被指向的活动对象即销毁。但是window不会被销毁。

 

                                             (PS:橡皮擦太小了,没擦干净)

 

 

 

 

闭包是什么呢? 官方解答是有权去访问函数内的变量。

我们现在来写一个函数:

 
    function foo(){
        var n = 0;
   //返回了一个函数。 这个函数的n 是从foo里面找的n。
return function getNum() { n++; console.log(n);
       return n; } }
var fn = foo();
  fn();

预解析就会多了一步:在执行foo的时候,也就是创建活动对象之后,会再执行 getNum的入栈步骤。getNum被调用时也会创建一个活动对象。但是最后并不会销毁。

因为fn指向了这个闭环回路。

简单的讲:这个函数被保存在了内存之中,并且一直可以通过fn访问到。

 

 

 

 

函数调用结束后:如果用fn指向这个getNum的作用域链对象。只要fn到getNum的指向没有消失。那么就可以一直访问到存储在内存的n.

闭包的核心就是getNum的活动对象没有被销毁,即使fn指向不是这个getNum 这个东西封闭的环也不会注销,会一直在内存中,这也是闭包的缺点,容易造成内存泄漏。

我们现在来梳理一下闭包的步骤:

1.函数内部嵌套子函数,

2.子函数得到父函数的值。

3.把内层函数返回出去。(但闭包的创建不止这个形式。还有其他的。)

 

 

 

 

 

 

 

 

 

 

 

  

  


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM