zoukankan      html  css  js  c++  java
  • js--闭包的理解

    从技术上来讲,在JS中,每个function都是闭包,因为它总是能访问在它外部定义的数据。

    当该内部函数在外部函数外被调用,就生成了闭包。

    函数内部可以直接读取全局变量。

    闭包就是能够读取其他函数内部变量的函数。

    在本质上,闭包就是将函数内部和函数外部连接起来的一座桥梁。

    举例:我们在函数lazy_sum中又定义了函数sum,并且,内部函数sum可以引用外部函数lazy_sum的参数和局部变量,当lazy_sum返回函数sum时,相关参数和变量都保存在返回的函数中,这种称为“闭包(Closure)”的程序结构拥有极大的威力。

    闭包经常用于创建含有隐藏数据的函数(但并不总是这样)。 代码如下:

        <script type="text/javascript">
            var db = (function() {
            // 创建一个隐藏的object, 这个object持有一些数据
            // 从外部是不能访问这个object的
                var data = {};
            // 创建一个函数, 这个函数提供一些访问data的数据的方法
                return function(key, val) {
                    if (val === undefined) { return data[key] } // get
                    else { return data[key] = val } // set
                }
            // 我们可以调用这个匿名方法
            // 返回这个内部函数,它是一个闭包
            })();
            db('x'); // 返回 undefined
            db('x', 1); // 设置data['x']为1
            db('x'); // 返回 1
            // 我们不可能访问data这个object本身
            // 但是我们可以设置它的成员
        </script>


    ------常见闭包问题-----
     /*输出的都是5*/
            function init() {
                var pAry = document.getElementsByTagName("p");
                for( var i=0; i<pAry.length; i++ ) {
                    pAry[i].onclick = function() {
                        alert(i);
                    }
                }
            }
            /*解决方法一:正常输出 依次 0,1,2,3,4
                    function init() {
                        var pAry = document.getElementsByTagName("p");
                        for( var i=0; i<pAry.length; i++ ) {
                            pAry[i].i = i;
                            pAry[i].onclick = function() {
                                alert(this.i);
                            }
                        }
                    }
                    */
                    /*解决方法二:正常输出 依次 0,1,2,3,4
            function init() {
                var pAry = document.getElementsByTagName("p");
                for( var i=0; i<pAry.length; i++ ) {
                    pAry[i].onclick = Function('alert('+i+')');
                }
            }*/
    
    
    
     
     

     ----------------------

    JavaScript闭包例子

    function outerFun()
     {
      var a=0;
      function innerFun()
      {
       a++;
       alert(a);
      }    
     }
    innerFun()

    上面的代码是错误的.innerFun()的作用域在outerFun()内部,所在outerFun()外部调用它是错误的.

    改成如下,也就是闭包:

    Js代码

    function outerFun()
    {
     var a=0;
     function innerFun()
     {
      a++;
      alert(a);
     }
     return innerFun;  //注意这里
    }
    var obj=outerFun();
    obj();  //结果为1
    obj();  //结果为2
    var obj2=outerFun();
    obj2();  //结果为1
    obj2();  //结果为2

    什么是闭包:

    当内部函数 在定义它的作用域 的外部 被引用时,就创建了该内部函数的闭包 ,如果内部函数引用了位于外部函数的变量,当外部函数调用完毕后,这些变量在内存不会被 释放,因为闭包需要它们.

    --------------------------------------------------------------------------------------------------------

    再来看一个例子

    Js代码

    function outerFun()
    {
     var a =0;
     alert(a);  
    }
    var a=4;
    outerFun();
    alert(a);

    结果是 0,4 .  因为在函数内部使用了var关键字 维护a的作用域在outFun()内部.

    再看下面的代码:

    Js代码

    function outerFun()
    {
     //没有var
     a =0;
     alert(a);  
    }
    var a=4;
    outerFun();
    alert(a);
    结果为 0,0 真是奇怪,为什么呢?

    作用域链是描述一种路径的术语,沿着该路径可以确定变量的值 .当执行a=0时,因为没有使用var关键字,因此赋值操作会沿着作用域链到var a=4;  并改变其值. 

    --------------------

    四、闭包的用途

    闭包可以用在许多地方。它的最大用处有两个,一个是前面提到的可以读取函数内部的变量,另一个就是让这些变量的值始终保持在内存中。

    怎么来理解这句话呢?请看下面的代码。


    Js代码

      function f1(){

        var n=999;

        nAdd=function(){n+=1}

        function f2(){
          alert(n);
        }

        return f2;

      }

      var result=f1();

      result(); // 999

      nAdd();

      result(); // 1000

    在这段代码中,result实际上就是闭包f2函数。它一共运行了两次,第一次的值是999,第二次的值是1000。这证明了,函数f1中的局部变量n一直保存在内存中,并没有在f1调用后被自动清除。

    为什么会这样呢?原因就在于f1是f2的父函数,而f2被赋给了一个全局变量,这导致f2始终在内存中,而f2的存在依赖于f1,因此f1也始终在内存中,不会在调用结束后,被垃圾回收机制(garbage collection)回收。

    这段代码中另一个值得注意的地方,就是“nAdd=function(){n+=1}”这一行,首先在nAdd前面没有使用var关键字,因此 nAdd是一个全局变量,而不是局部变量。其次,nAdd的值是一个匿名函数(anonymous function),而这个

    匿名函数本身也是一个闭包,所以nAdd相当于是一个setter,可以在函数外部对函数内部的局部变量进行操作。

    http://www.jb51.net/article/24156.htm  前端必知的闭包知识及其应用

  • 相关阅读:
    Power BI for Office 365(八)共享查询
    Power BI for Office 365(七) Power BI站点
    Power BI for Office 365(六)Power Map简介
    Power BI for Office 365(五)Power View第二部分
    Power BI for Office 365(四)Power View第一部分
    Power BI for Office 365(三)Power Pivot
    Power BI for Office 365(二)Power Query
    java 继承、重载、重写与多态
    Android 热修复方案Tinker(一) Application改造
    阿里最新热修复Sophix与QQ超级补丁和Tinker的实现与总结
  • 原文地址:https://www.cnblogs.com/lanyueff/p/4602431.html
Copyright © 2011-2022 走看看