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

    一、闭包的概念

       闭包就是能够读取其他函数内部变量的函数,可以把闭包简单理解成"定义在一个函数内部的函数。

    二、闭包的用途

      它的最大用处有两个。

      用图1:读取函数内部的变量。

      要理解闭包,首先必须理解Javascript特殊的变量作用域。变量的作用域无非就是两种:全局变量和局部变量。Javascript语言的特殊之处,就在于函数内部可以直接读取全局变量。在函数外部自然无法读取函数内的局部变量(函数内部声明变量的时候,一定要使用var命令。如果不用的话,你实际上声明了一个全局变量!)。

      那么,如何从外部读取局部变量?那就需要在函数f1的内部,再定义一个函数f2,f2可以读取f1中的局部变量,只要把f2作为返回值,我们就可以在f1外部读取它的内部变量了!。

      

    function f1() {    
        var n = 999;    
        function f2() {      
            alert(n);     
        }    
        return f2;  
    }  
    var result = f1();  
    result(); // 999

      用图2:让变量的值始终保持在内存中。

    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,可以在函数外部对函数内部的局部变量进行操作。

    三、闭包的优缺点

      缺点:
      内存浪费

      优点:

      1.减少全局变量

    function add() {
        var a = 0;
        a++;
        return a;
    }

      调用一次:add();//返回结果是1

      再调用一次:add();//返回结果依然是1

      因为a在函数中是局部变量,每次都被初始化,如果要实现1,2,3的效果需要把a放到外面进行全局变量。

      闭包可以实现避免全局变量

    function add() {
        var a = 0;
        return function() { 
            a++;
            alert(a);
        }
    };

      调用  

    var result = add(); //add()函数返回一个匿名函数,这个函数保留了a的词法环境,即一个闭包,所以在调用的时候a的值从0开始
    result(); //返回1
    result(); //返回2

      2.减少参数传递

    function calFactory(base) {
        return function(max) {
            var total = 0;
            for (var i = 0; i <= max; i += ) {
                total += i;
            }
            return total + base;
        }
    }

      调用

    var adder=calFactory(2);  //calFactory每调用一次都会产生一个新的闭包
    alert(adder(3))//返回结果为8
    alert(adder(2))//返回结果为5

      3.封装变量

    (functon() {
        var m = 0;
        function getM() { //
            return m
        };
        function setM(value) {
            m = value
        };
        window.g = getM; //返回到window上
        window.s = setM; //返回到window上
    
    })();
    s(12);
    alert(g()); //12

    四、典型应用:给ul里的每个li添加点击事件,让他们弹出自己的索引

    var aLi = document.getElementsByTagName('li');
    for (var i = 0; i <= aLi.length; i++) {
        aLi[i].onclick = (function(i) {
            return function() {
                alert(i)
            }
        })(i); //把i传进去
    }
  • 相关阅读:
    大数据内存模型(二级指针)
    多线程函数指针
    返回函数指针的函数
    动态分配二维数组指针
    俄罗斯方块学习笔记
    tailf
    tail
    cut
    split
    paste
  • 原文地址:https://www.cnblogs.com/superlizhao/p/7999745.html
Copyright © 2011-2022 走看看