zoukankan      html  css  js  c++  java
  • 大白话理解闭包及相关笔试题

    我们先来一个最简单的函数(如下)。

     function fn(){
            var num = 5;
            num+=1;
            alert(num);
      }  
      fn(); //6     第一次调用是6 
      fn(); //6     第二次调用还是6

    理由: 函数一旦调用里面的内容就会被销毁,下一次调用又是一个新的函数。

    第一次调用后打印出6,第二次调用又相当于重新进行第一次调用,依旧是6。

    这个时候,就需要我们的闭包来出面解决,那么我们先来了解下什么是闭包吧。

    闭包可以解决函数外部无法访问函数内部变量的问题

    通过闭包我们可以让函数中的变量持久保持。来看

    function foo(c){
      var num = c;
      return function A(){
        num++;
        return num;
      }
    }
    var b = foo(5); //b = function A
    b();//6
    b();//7

    我们执行的是函数b(从foo返回出来的),每次调用函数b,并没有重新执行foo,所以也就不会每次给num重新赋值5。

    至于为什么会出现累加呢,这是因为函数foo执行完后,其内部的的A函数里面对num有引用,所以foo的作用域以及变量num被保留在了函数A中,返回给了b。

    现在,我们就能在外界通过函数b来访问foo内部的变量num了。

    这就是闭包,我们通过返回一个函数打通了函数内部与外界的桥梁。

    我们首页定义了一个fn函数,里面有个num默认为0,接着返回了一个匿名函数(也就是没有名字的函数)。我们在外部用f接收这个返回的函数。这个匿名函数干的事情就是把num加1,还有我们用来调试的alert。

    这里之所以执行玩这个函数num没有被销毁是因为那个匿名函数的问题,因为这个匿名函数用到了这个num,所以没有被销毁,一直保持在内存中,因此我们f()时num可以一直加

     var name = "The Window";
      var object = {
        name : "My Object",
    
        getNameFunc : function(){
          return function(){
            return this.name;
          };
        }
      };
    
     alert(object.getNameFunc()());

    object.getNameFunc()返回了一个匿名函数:

    function(){   
    return this.name;   
    };
    this对象是在运行时基于函数的执行环境绑定的, 
    匿名函数的执行环境具有全局性, 
    因此匿名函数的this指向window


     var name = "The Window";
    
      var object = {
        name : "My Object",
    
        getNameFunc : function(){
          var that = this;
          return function(){
            return that.name;
          };
    
        }
    
      };
    
     alert(object.getNameFunc()());
    应用场景:
    循环绑定的问题
    <ul class="list">
          <li class="bloc">1</li>
          <li class="bloc">2</li>
          <li class="bloc">3</li>
          <li class="bloc">4</li>
          <li class="bloc">5</li>
     </ul>
      var ali = document.querySelectorAll('ul li')
      for(var i = 0,l = ali.length;i < l;i++){
       ali[i].onclick = function(){
            console.log(i)  //5 5 5 5 5
        }
      }

    reason:

    我们绑定了五次onclik事件,无论你有没有触发后面的的函数,for循环都会执行。

    当你点击的时候,for循环已经执行完了,i 的值早已经变成了5。var 声明的i能够穿透作用域,每次触发点击事件时,函数内部的 i 也都是5。

    那么,我们应该想办法把每次循环时的 i 值保存下来呢。

    于是,通过闭包可以保存每次循环的 i 值,请看例子:

    for(var i = 0,l = ali.length;i < l;i++){
         ali[i].onclick = (function(j){
             return function(){
                  console.log(j)          
         } })(i) }
    for(var i = 0,l = ali.length;i < l;i++){
           (function(j){
               ali[j].onclick = function(){
                   console.log(j)  //5 5 5 5 5
            }
           })(i)
     }    
        

    通过立即执行函数后返回了一个函数的形式,把每次循环的 i 值通过传参放到了不同的函数中,

    每个函数都是一个独立的作用域,每个函数都有了各自的i值,互相不影响,现在就如我们期望的一样了,点击第几个li打印出第几个 li 的下标。


     
  • 相关阅读:
    MS CRM 2011 RC中的新特性(4)——活动方面之批量编辑、自定义活动
    最近的一些有关MS CRM 2011的更新
    MS CRM 2011 RC中的新特性(6)——连接
    MS CRM 2011 RC中的新特性(7)—仪表板
    参加MS CRM2011深度培训课程——第一天
    MS CRM 2011插件调试工具
    MS CRM2011实体介绍(四)——目标管理方面的实体
    MS CRM 2011 RC中的新特性(3)——客户服务管理方面
    MS CRM 2011 RC中的新特性(8)—数据管理
    ExtAspNet 登陆
  • 原文地址:https://www.cnblogs.com/renzm0318/p/8966640.html
Copyright © 2011-2022 走看看