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 的下标。


     
  • 相关阅读:
    又见Alice and Bob
    算法7-6:图的遍历——广度优先搜索
    算法7-5:图的遍历——深度优先搜索
    水池数目
    过河问题
    括号配对问题
    C# 客户端判断是否安装office03、07或WPS
    C# json
    开源cms
    可执行代码(Executable Code)目标代码(object code)
  • 原文地址:https://www.cnblogs.com/renzm0318/p/8966640.html
Copyright © 2011-2022 走看看