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

    关于闭包大家肯定不陌生, 刚知道闭包这个特性那会真的被折磨, 现在找个时间把这些都记下来, 希望能帮新人理解和记忆.

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

    闭包的格式有很多种, 但基本都是将一个嵌套函数中的内层函数返回到外层函数外面, 使外层函数体外也能访问和操作外层函数中"封住"的局部变量, 与此同时, 外层函数中的变量不会被销毁, 会"长久记忆".

    最常见的闭包:

    function outer(){
        var i = 100;              //保存于外层函数体内的局部变量
        return function(){     //用于返回内部函数
              console.log(i);   //内部函数体中对 "它" 自己的上下文中的变量进行了操作
        }
    }
        var inner = outer();
        inner();    

    闭包的形式知道了, 重点是怎么调用, 关于调用的方式有很多:

    第一种:

    function outer(){
        var i = 100;              
        return function(){
              i++;          
              console.log(i);   
        }
    }
        var inner1 = outer();
        var inner2 = outer();
        inner1();  //输出结果为 101;
        inner2();  //输出结果还是 101;

    这是为何呢? 原因是  当 外层函数每执行一次, 就会创建新的闭包, 即每次外层函数的执行都开辟新的内存空间, 虽然 inner1 和 inner2 都是函数的引用, 但每次返回的函数都是"新的", 所以 inner1 是 inner1, inner2 是 inner2.

    第二种

    function outer(){
        var i = 100;              
        return function(){
              i++;          
              console.log(i);   
        }
    }
        var inner1 = outer();
        var inner2 = inner1;
        inner1(); //输出 101
        inner2(); //输出 102

    这种调用方式和第一种相比就很好理解了, 因为 inner1 和 inner2 都是"同一个函数"的引用, 所以出现 101 和 102 也就通了.

    第三种

    function fo(){
        var i = 0;
        return function(n){
        return n + i++;
        }
    }
    
    var f = fo();      //现在变量f是一个函数的引用
    var a = f(15);     //输出 15, i此时的值是0, 不是undefind, 闭包能够记住自己认识变量i
    var b = fo()(15);  //输出 15, fo()会返回新的内层函数, 也就是说产生了新的闭包(对比第一种理解), i已经被清零
    var c = fo()(20);  //输出 20, 同理
    var d = f(20);    //输出 21

    第三种函数做了稍稍改变, 内层函数中要传入形式参数, 其实道理是一样的.

    第四种

    function fo(m){
        return function(n){
        return m + n;
        }
    }
    
    var f = fo(1);      //变量 f 是一个内层函数的引用, 此时 f 已"记住" f 自己中要调用的 m 的值为 1
    var a = f(2);       //输出 3, 因为闭包的存在, 所以在 f(2) 执行时, f 内部的 m 是 1
    var b = fo(10)(1);  //输出 11, 每当外层函数 fo 执行一次, 都会产生新的闭包并返回一个函数
    var c = fo(10)(2);  //输出 12。同理。
    var d = f(3);       // 和 f(2) 同理.

    第五种

    其实第五种来说, 不单单是闭包的影响, 还有就是关于"异步"的一些概念, 就是浏览器给元素添加监听是要消耗时间的, 所以在给一个类数组中的元素通过循环添加监听是不能直接添加的.下面是 html 结构.

        <ul>
            <li></li>
            <li></li>
            <li></li>
            <li></li>
            <li></li>
        </ul>

    下面是对应的 JS 代码:

    
    

    var lis = document.getElementsByTagName("li");
    for(var i = 0, length = lis.length; i < length; i++){
      lis[i].onclick = function (){
        console.log("我被点击了, 我是第" + i);
      };
    }

    初学者可以试试, 会发现每个 li 触发点击后再控制台输出的都是 "我被点击了, 我是第 5", 原因是 当 浏览器给 元素添加监听时, 不会阻塞程序的执行, 就是说在给 lis[0] 添加事件监听时, for 循环还在走, i 还在 ++.

    解决方法最好用的就是 IIFE(即立即执行函数):

    var lis = document.getElementsByTagName("li");
    for(var i = 0, length = lis.length; i < length; i++){
        lis[i].onclick = (function(i){
                    return function (){
                        console.log("我被点击了, 我是第" + i);
                                    };
                })(i);
    }        

    外层函数是立即执行的, 并且把 i 当做参数传入函数体, 因此返回的内层函数就会拿到"合适的" i 值.

    以上是我对闭包的一些理解, 在此抛砖引玉, 有误导之处还请不吝指点 ^^.

  • 相关阅读:
    HDU 5938 Four Operations 【贪心】(2016年中国大学生程序设计竞赛(杭州))
    HDU 5935 Car 【模拟】 (2016年中国大学生程序设计竞赛(杭州))
    HDU 5934 Bomb 【图论缩点】(2016年中国大学生程序设计竞赛(杭州))
    HDU 5933 ArcSoft's Office Rearrangement 【模拟】(2016年中国大学生程序设计竞赛(杭州))
    HDU 5929 Basic Data Structure 【模拟】 (2016CCPC东北地区大学生程序设计竞赛)
    【转】LaTeX 符号命令大全
    HDU 5922 Minimum’s Revenge 【模拟】 (2016CCPC东北地区大学生程序设计竞赛)
    HDU 5927 Auxiliary Set 【DFS+树】(2016CCPC东北地区大学生程序设计竞赛)
    数据结构之稀疏矩阵
    C++中引用(&)的用法和应用实例
  • 原文地址:https://www.cnblogs.com/vlovecode/p/6031404.html
Copyright © 2011-2022 走看看