zoukankan      html  css  js  c++  java
  • 从一道思考题说说闭包

    这是一道从阮一峰老师的一篇博客《学习Javascript闭包(Closure)》看到的思考题。(PS:开始的时候,是从阮一峰老师的博客看到的这道思考题。后来看《JavaScript高级程序设计》(第3版)(下面简称《JS高程》)才发现,原来这就是书中的例子啊。^_^|||)

    思考题原代码如下,请试着理解两段代码的运行结果:

    代码片段一

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

    代码片段二

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

     

    下面我们尝试分析一下解答这道思考题的思路。

    对于代码片段一:

    1.开始声明了一个变量name和一个对象object;

    2.对象object的第二个属性值是一个函数,这个函数里面嵌套了另一个函数;

    3.代码最后是一个alert(),参数值是对对象object的第二个属性值中嵌套的子函数进行调用的结果。从这地方开始有一点绕了,我们一步一步来:

      1) object.getNameFunc是取object的第二个属性值,也就是函数 function(){ return function(){ return this.name; }} ;

      2) object.getNameFunc()是对函数 function(){ return function(){ return this.name; }} 的调用,得到函数 function(){ return this.name; } ;

      3) object.getNameFunc()()是对函数 function(){ return this.name; } 的调用,得到返回值 this.name 。

    4.所以alert()运行结果就是弹出 this.name 的值。关键现在 this.name 值是什么。

        

    对于代码片段二:

    类似于上面,最后我们可以推出,alert()运行结果就是弹出 that.name 的值。现在 that.name 值是什么。

     

    《JS高程》中对闭包的解释很简单:闭包是有权访问另一个函数作用域中的变量的函数。创建闭包的常见方式,就是在一个函数内部创建另一个函数。

    很多人讲闭包还会讲一些附加的条件,比如这个函数还要访问外部变量等等,目的是方便读者了解闭包的特性。然而这可能令初学者更为困惑,到底什么是闭包。其实《JS高程》中的定义也不够直接,第一句是通过特征归纳出了闭包的定义,而凡是不能从事物本质给出定义的结论,都不能较好的帮助我们认识事物本身。我觉得就初学者来说,只要认准一种形式的闭包就可以了,即函数中嵌套了子函数,这个子函数就是一个闭包,这也是书中提到的常见形式。例子中, function(){ return this.name; } 就是闭包。

     

    这道思考题看起来似乎更多的是在帮助我们理解this,但其实如果缺少对闭包特性的掌握,可能也不太容易搞清楚代码运行的结果。

    第一个例子中, alert(this.name); 相当于在全局作用域中访问this,此时this指向window,就是相当于 alert(window.name); 。所以,结果就是“The Window”。

    第二个例子中,that是在getNameFunc属性值中定义的函数里声明的,that被赋值为this。object.getNameFunc()表示getNameFunc属性值中定义的函数被作为object的方法调用,所以this指向object,that与this指向相同,所以that也指向object。而that在闭包的作用域链上,除非闭包被销毁,否则即使that通过return被返回,也依然指向object。所以,结果就是“My Object”。

     

    我们来看另外一个例子,下面是一段HTML代码:

     1     ……
     2     <body>
     3         <ul>
     4             <li>red</li>
     5             <li>green</li>
     6             <li>blue</li>
     7             <li>yellow</li>
     8             <li>pink</li>
     9         </ul>
    10     </body>
    11     ……

    现在,我通过getElementByTagName()获取到所有的li标签,这是一个类似数组的集合。然后,我要在页面中通过单击各个li让控制台中打印出其对应的下标值。

    如果不采用闭包,我们通常会这么做:

     1         <script>
     2             window.onload=function(){
     3 
     4                 var lis=document.getElementsByTagName('li');
     5 
     6                 for(var i=0;i<lis.length;i++){
     7                     lis[i].index=i;
     8                     lis[i].onclick=function(){
     9                             console.log(this.index);
    10                     };
    11                 }
    12             }
    13         </script>

    有了闭包之后,我们可以这样:(代码中只给出for循环的代替部分,这种方法中只有这部分与上面是不一样的)

    1                 for(var i=0;i<lis.length;i++){
    2                     //下面是一个函数自执行的写法
    3                     (function(j){
    4                         lis[j].onclick=function(){
    5                             console.log(j);
    6                         };
    7                     })(i);    //  这一行也可以这样写 "}(i));"
    8                 }

    或者这样:(同样只给出for循环的代替部分)

    1                 for(var i=0;i<lis.length;i++){
    2                     lis[i].onclick=(function(j){
    3                         return function(){
    4                             console.log(j);
    5                         }
    6                     })(i);
    7                 }

    最后,《JS高程》提到“由于闭包会携带包含它的函数的作用域,因此会比其他函数占用更多的内存。过度使用闭包可能会导致内存占用过多,我们建议读者只在绝对必要时再考虑使用闭包。”

    知识共享许可协议
    本作品采用知识共享署名 4.0 国际许可协议进行许可。

  • 相关阅读:
    软件架构阅读笔记04
    软件架构阅读笔记03
    TortoiseGit和intellij idea配置秘钥
    linux关闭在线登录用户
    汉化gitlab
    GitLab服务器搭建
    redis 中如何切换db
    弹性伸缩问题
    Filebeat+Logstash自定义多索引
    logstash
  • 原文地址:https://www.cnblogs.com/fortunel/p/6380075.html
Copyright © 2011-2022 走看看