zoukankan      html  css  js  c++  java
  • 那些年,我们误解的 JavaScript 闭包

    说到闭包,大部分的初始者,都是谈虎色变的。最近对闭包,有了自己的理解,就感觉。其实我们误解闭包。也被网上各种说的闭包的解释给搞迷糊。

    一句话:要想理解一个东西还是看权威的东西。

    下面我来通俗的讲解一个闭包的知识。(建议大家去读JavaScript权威指南)

    我们先弄明白几个问题:

    1、作为命名空间的函数:

    在函数中声明的变量在整个函数体内都是可见(包括嵌套的函数)在函数的外部不是可见的。不在任何函数内声明的是全局变量

    ===》也就是说:一个函数它就是一个作用域,不管你里面有什么东西。他们都是一家子。

    function fn(){

      var b1,b2.....;

      function a1(){}

      function a2(){}

      ..........//不管你是有多少函数,多少变量。你们都被fn用{}包围着,那么你们在fn下都是相互透明的。

    }

    2、函数只有在调用的时候,才会执行,函数名是函数的引用。(说白了就是在函数名的后面加个括号呗)

     function fn(){

        alert("调用我,我才会alert")

      }

    fn()//在函数名的后面加了一个()这个函数才会执行。===============这点大家肯定很明白的吧

    3、函数本身也是一个对象:(JavaScript中一切皆是对象,{个别的特例,咱暂且不说})

      对象:可以有属性 、方法。对象的内的方法调用自己的属性,=============这个大家也肯定没有问题吧

      也就是说,一个对象的内部是一家族。

      var obj ={

      var name;

      function getName(){}// getName() 方法和name属性,都是在obj这个对象的作用域内的==========其实就是上面1所称述的那样。

    }

      

    好了,如果你理解,上面这三个知识点,你可以继续看下面的了。【问问自己理解这三个知识点没????????????????????】

    闭包

    JavaScript权威指南中有一段关于闭包的话。

    函数的执行依赖于变量的作用域,这个作用域是在函数定义时决定的,而不是函数调用时决定的。

    总结:函数体内的变量都可以保存在这个函数的的作用域内。这种特性在计算机科学内叫做闭包

    这是一个很正常的东西啊。一个函数圈了一个作用域,然后一些代码,在我的区域里面保存了。不就是我的作用域下的吗?

    就像:

      function a(){

        function b(){}

    }

    不要告诉,现在的b是属于 外人的。就像上文1说的那样,a这个函数是一个命名空间,一个作用域。在我的作用域里面的东西,怎么可能是别人的额。

    ===所以:在我作用域里面的,是我家的,可以拿我家的东西。(函数体内可以保存变量在这个函数的作用域。之所以说官方强调闭包,就是因为JavaScript函数内保存变量时,和其他语言,Java。。不太一样,有个作用域链等等。。。。不先管他们。)

    ======总之======【我们就理解为:闭包的特性的初衷就是在一个函数作用域内保存变量。一个狠狠正常的事情啊,我家的东西放我家啊,我爱我家】

    例子:村子与张三家族的关系。

    var area ="这是村里的东西";

    function zhangjia(){
      var area ="这是张家的东西";
      function getArea(){
      return area;
      }
      return getArea();
    }

    zhangjia();            //这是张家的东西

    如果我这样的话;

    var area ="这是村里的东西";

    function zhangjia(){
      var area ="这是张家的东西";
      function getArea(){
      return area;
      }
      return getArea;
    }

    var  getSomeArea = zhangjia();//返回的函数的引用,将此引用赋给一个变量,那么getSomeArea这个变量同样是引用张家的getArea方法啊。

    getSomeArea();     //现在,调用这个方法(加())不就是调用张家的那个getArea吗。拿到的area还是张家的area啊。因为,在一个开始的时候,人家就是属于张家的,当然取张家的东西。

    ===============【函数的执行依赖于变量的作用域,这个作用域是在函数定义时决定的,而不是函数调用时决定的。】多好的理解,很正常的逻辑啊

    但是但是,要说但是了,正式由于JavaScript闭包存储变量的特殊性,就会出现一些问题。

    接着看:我们看看这个经常被网上的大神拿来用的一个例子。

    var result=[];
    function foo(){
      var i= 0;
      for (;i<3;i=i+1){
        result[i]=function(){
        alert(i)
        }
      }
    };
    foo();//foo是一个函数的引用,foo()就是调用这个函数,没有问题吧。
    result[0](); // 3
    result[1](); // 3
    result[2](); // 3

    为啥,为啥,为啥都是3 。

    我们期望的是每次都把对应的i值alert出来。但是结果却是这样。

    来:一个函数只要在调用的时候,才会执行。(熟悉不??????)

    result[i] = function(){alert(i)} 这不就是把一个函数赋值给一个变量,这个变量装的是函数的引用,注意---就是引用,就像上面说的没有执行呢。

    当我们执行的时候:

    result[0]() -------发生 了什么?????????????????????????????????

    ????????????????

    对啊,就是那个闭包的问题啊;方法会去自己家里拿i值。哪个家?????foo这个家里啊。这是时候的i是3 了。alert(i)不就是3了。

    多么多么正常的正常的事 啊。狠狠正常的逻辑

    解决呢??

    有人说,既然你说没有执行,那我就立即执行,循环的时候就执行,不光是一个引用在那里。。。

    。。。。好,聪明

    var result=[];
    function foo(){
      var i= 0;
      for (;i<3;i=i+1){
        result[i]=(function(){
          alert(i);
        })();//立即执行,返回的是一个结果给result ,不是引用了。
      }
    };
    foo();

    如果还想要result[i]()这种方式调用,咋办呢?

    这个家族里的东西,你在拿到你的小家里去吧。在你家保存下

    var result=[];
    function foo(){
        var i= 0;
        for (;i<3;i=i+1){
          result[i]=(function(j){
            return function(){
            alert(j)
            }
          })(i);//作为一个参数传到小家去,虽然现在result[i]还是一个引用,引用一个函数,但是这个函数保存了每次循环时的对应的i值。
      }
    };
    foo();

    result[1] //1

    综上所述:

      闭包本来就是一个很正常的逻辑。但是由于他的实现方式涉及作用域链,作用域之间的引用问题,显得他很难理解。

      希望带着我说的额这些,多去理解一下。你发现,人家本来就是一个很正常的逻辑问题:我爱我家啊。。。。。。。。。。。

  • 相关阅读:
    Java中字符串中子串的查找共有四种方法(indexof())
    idea常用快捷键
    用hive或mr清洗app数据
    使用kafka作为生产者生产数据到hdfs(单节点)
    使用kafka作为生产者生产数据到hdfs
    c++ map的使用
    c++ set集合的使用
    c++ 木块问题
    c++ 大理石
    c 蛇形数字
  • 原文地址:https://www.cnblogs.com/smallstudent/p/5462559.html
Copyright © 2011-2022 走看看