大白话理解闭包及相关笔试题

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

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


 
posted @ 2019-05-16 19:40  灰姑娘的冰眸  阅读(176)  评论(0编辑  收藏  举报