热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

分分钟搞懂JS-闭包函数

1抛开概念!直接上代码,看实例23vari100;4functionadd1(){5alert(i);6i++;7}8fun
 1 //抛开概念!直接上代码,看实例
 2 
 3 var i=100;
 4 function add1(){
 5    alert(i); 
 6    i++;
 7 }
 8 function add2(){
 9    var j=100;
10    alert(j); 
11    j++; 
12 }
13 
14 //测试;
15 
16 //    add1(); //100
17 //    add1(); //101
18 //    add1(); //102
19 //    
20 //    add2(); //100
21 //    add2(); //100
22 //    add2(); //100
23 
24 /*为什么呢 原因很简单
25 i 是全局变量,只有页面关闭的时候,才会被GC回收;
26 j 是局部变量,函数执行完毕后就 被GC 回收;
27 
28 问:有没有办法将j 变成"全局变量"呢?
29 A同学答:有,将j写在外面(尼玛,傻逼啊)
30 B同学答,用return(有点接近了) 然后用全句变量来接收;
31 C同学答:闭包(完美)    
32 */
33 function add3(){
34   var j=100;
35   function fun(){
36    alert(j);
37    j++;
38   }
39    return fun; //注意这里;
40 }
41 
42 /*
43 测试:
44 
45 var obj=add3(); //执行add3()函数,同时返回了fun的引用(也就是fun的函数体)
46 
47 //直接alert(obj) 你会看到他的函数体- function fun(){....} 再加上一个括号(),就可以执行了
48 
49    obj(); //100
50 
51    obj(); //101
52 
53    obj();//102
54 
55  */

 

当函数a的内部函数b 被函数a 外的一个变量引用的时候,就创建了一个闭包。

简而言之,闭包的作用就是在a执行完并返回后,闭包使得Javascript的垃圾回收机制GC不会收回a所占用的资源,因为a的内部函数b的执行需要依赖a中的变量。这是对闭包作用的非常直白的描述,不专业也不严谨,但大概意思就是这样,理解闭包需要循序渐进的过程。

那么我们来想象另一种情况,如果a返回的不是函数b,情况就完全不同了。因为a执行完后,b没有被返回给a的外界,只是被a所引用,而此时a也只会被b引 用,因此函数a和b互相引用但又不被外界打扰(被外界引用),函数a和b就会被GC回收

最后,如果你能看懂这段代码你就理解了闭包!

 1    var name="window";
 2    var object={
 3      name:"my object",
 4      getName:function (){
 5          return function (){
 6              return this.name; 
 7          }
 8      }
 9       
10   }
11  alert(object.getName()()); //window

闭包的多种写法:

写法一:

  function f1(){
     var index=1;
     function f2(){
        alert(index);
        index++; 
     }
     return f2;
  }
  //调用
  var test=f1();
  test(); //1
  test(); //2
  test(); //3

写法二:

  function outer(){
      var index=1;
     return function(){ //使用匿名函数
         alert(index);
         index++;
     }
  }
 var bibao=outer();
  bibao();
  bibao();
  bibao();

写法三: 

var outer=(function (){
      var index=1;
      return function (){
         alert(index);
         index++;  
      }
    
})();

outer();
outer();
outer();

写法四:

var outer=null;
(function (){
    var index=1;
    function inner(){
      alert(index++);    
    };
    outer=inner;
})();
outer();
outer();
outer();

总之就是函数之间的嵌套,变量之间的互相引用;

Javascript的垃圾回收原理

(1)、在Javascript中,如果一个对象不再被引用,那么这个对象就会被GC回收; 
(2)、如果两个对象互相引用,而不再被第3者所引用,那么这两个互相引用的对象也会被回收。

 总结:

 

 

实例:

html代码:

          <ul>
                    <li>123li>
                    <li>456li>
                    <li>789li>
                    <li>010li>
            ul>

 js代码:(错误方式) 

window.Onload= function(){
            var lis = document.getElementsByTagName('li');
            var len=lis.length;
            for (var i=0;i){
                    lis[i].onclick = function(){        //当点击时for循环已经结束
                    alert(i);
                    };
            }
    }

js代码:(错误方式)

window.Onload=function (){
     var index=0;
     var lis=document.getElementsByTagName("li");
     var len=lis.length;
     for(var i=0;i){
         lis[i].onclick=function (){
            alert(index);  //这样做,避免了i直接等于3,但是,却没有绑定到指定的对象上滴呀
            index++;
            if(index==len){
                index=0;
            }
         }
     }
}

js代码:(改进方式一)面向对象+this关键字的使用

window.Onload=function (){
  var lis=document.getElementsByTagName("li");
  var len=lis.length;
  for(var i=0;i){
      lis[i].index=i; //给每个变量动态的绑定一个属性,并赋值
      lis[i].Onclick=function (){
          var temp=this.index; //然后使用this关键字;
          alert(temp);  
      }
  }
}

js代码改进二:让i独立出来,index作为他的一个“副本”! i的变化不再影响到我们index

function showInfo(obj,index){
   obj.onclick=function (){
     alert(index);   
   }
}

window.onload=function (){
  var lis=document.getElementsByTagName("li");
  var len=lis.length;
  for(var i=0;i){
     showInfo(lis[i],i);//i的改变和 index无关滴呀  
  }
}

原理解析一:

   var index=1;
   
   function change1(){
     index=index+1;
   }
   
   function change2(){
    index=index+2;
   }
   change1();
   change2();
   alert(index); //4

原理解析二:

   function change1(val){
     var temp=val;
     temp=temp+1;
   }
   
   function change2(val){
     var temp=val;
     temp=temp+2;
   }
   
   change1(index);
   change2(index);
   alert(index);
   //这样这不会改变;

最总版本:(关键-传递副本)

 var index=1;
  (function (val){
     val=100;  
  })(index);
   
  (function (val){
     val=10000;  
  })(index);
   
   alert(index);

js代码:(闭包实现)模块化代码,减少全局变量的污染-最好的方式;

我们需要在每次循环时为变量 i 值创建一个拷贝,重点在:模块话代码,形成一个独立的区域;

window.Onload=function (){
     var lis=document.getElementsByTagName("li");
     var len=lis.length;
     for(var i=0;i){
         (function (e){
              lis[e].onclick=function (){
                 alert(e);  
              }
         })(i); //形成一个独立的区域互补干扰
     }
}

继续扩展,这段代码是不是闭包?还是仅仅是一个你们匿名函数的自执行呢? 

         (function (e){
              lis[e].onclick=function (){
                 alert(e);  
              }
         })(i)

 

 //闭包概念:闭包是指某种程序语言中的代码块允许一级函数存在并且
  //在一级函数中所定义的自由变量不能被释放,直到一级函数释放前,
  //一级函数外也能应用这些未释放的自由变量;
 var shit=function (y){
    var x=y;
    return function (){
      alert(x++); //这里调用了一级函数的局部变量x
      //上下连个交换着尝试
      alert(y--); //这里调用参数变量,是自变量;    
    }}(5);
    
shit();  // 5 5
shit();  // 6 4
shit();  // 7 3

 

关于内存泄露的问题;

function closure(){
   var div=document.getElementById("div1");//div用完之后一直驻留在内存中
   div.Onclick=function (){
      alert(div.innerHTML);  //这里导致了内存泄露得呀
      //长期扎住在内存中得,没有得到是释放;   
   }
}

//优化:
function closure2(){
  var div=document.getElementById("div1");
  var text=div.innerHTML;
   div.onclick=function (){
      alert(text);  //这里导致了内存泄露得呀
      //长期扎住在内存中得,没有得到是释放;   
   }
   div=null;
}

再推荐一篇关于闭包的好文章

http://segmentfault.com/a/1190000000652891

应用

看我另外一篇文章:

js 动画实现原理,就是闭包的一个典型应用的呀;

 

 

 

 

 

 


推荐阅读
  • 本文深入剖析了jQuery的架构设计与实现原理。jQuery的总体结构采用了一个自执行匿名函数的形式,该函数接收`window`和`undefined`作为参数,并在内部定义了一个局部的jQuery副本,以确保其内部变量和方法不会污染全局命名空间。这种设计不仅提高了代码的封装性和安全性,还使得jQuery能够更好地与其他JavaScript库兼容。通过详细分析这一架构,读者可以更好地理解jQuery的核心机制及其高效运行的原理。 ... [详细]
  • 在 Angular Google Maps 中实现图片嵌入信息窗口的功能,可以通过使用 `@agm/core` 库来实现。该库提供了丰富的 API 和组件,使得开发者可以轻松地在地图上的信息窗口中嵌入图片。本文将详细介绍如何配置和使用这些组件,以实现动态加载和显示图片的功能。此外,还将探讨一些常见的问题和解决方案,帮助开发者更好地集成这一功能。 ... [详细]
  • 本文介绍了UUID(通用唯一标识符)的概念及其在JavaScript中生成Java兼容UUID的代码实现与优化技巧。UUID是一个128位的唯一标识符,广泛应用于分布式系统中以确保唯一性。文章详细探讨了如何利用JavaScript生成符合Java标准的UUID,并提供了多种优化方法,以提高生成效率和兼容性。 ... [详细]
  • 在Bugku Web CTF实战演练中,通过细致的源代码检查,我们发现了一个隐藏的滑稽笑脸图标,进一步分析后成功找到了flag。此外,还探讨了如何利用计算器功能进行安全测试,提升了对Web漏洞的识别和利用技巧。 ... [详细]
  • 随着CRM版本的更新,某些功能可能不再可用。本文探讨了一种高效的替代方案,通过编写 `function loadFrom()` 来识别和区分不同的编辑窗口。该方法利用了Xrm.Page对象的特性,确保在不同版本的CRM中都能稳定运行。此外,文章还详细介绍了如何通过检测页面类型和上下文信息来优化用户体验。 ... [详细]
  • 本文深入探讨了CGLIB BeanCopier在Bean对象复制中的应用及其优化技巧。相较于Spring的BeanUtils和Apache的BeanUtils,CGLIB BeanCopier在性能上具有显著优势。通过详细分析其内部机制和使用场景,本文提供了多种优化方法,帮助开发者在实际项目中更高效地利用这一工具。此外,文章还讨论了CGLIB BeanCopier在复杂对象结构和大规模数据处理中的表现,为读者提供了实用的参考和建议。 ... [详细]
  • 如何高效启动大数据应用之旅?
    在前一篇文章中,我探讨了大数据的定义及其与数据挖掘的区别。本文将重点介绍如何高效启动大数据应用项目,涵盖关键步骤和最佳实践,帮助读者快速踏上大数据之旅。 ... [详细]
  • 在处理遗留数据库的映射时,反向工程是一个重要的初始步骤。由于实体模式已经在数据库系统中存在,Hibernate 提供了自动化工具来简化这一过程,帮助开发人员快速生成持久化类和映射文件。通过反向工程,可以显著提高开发效率并减少手动配置的错误。此外,该工具还支持对现有数据库结构进行分析,自动生成符合 Hibernate 规范的配置文件,从而加速项目的启动和开发周期。 ... [详细]
  • 在HTML5应用中,Accordion(手风琴,又称抽屉)效果因其独特的展开和折叠样式而广泛使用。本文探讨了三种不同的Accordion交互效果,通过层次结构优化信息展示和页面布局,提升用户体验。这些效果不仅增强了视觉效果,还提高了内容的可访问性和互动性。 ... [详细]
  • 本文探讨了利用Java实现WebSocket实时消息推送技术的方法。与传统的轮询、长连接或短连接等方案相比,WebSocket提供了一种更为高效和低延迟的双向通信机制。通过建立持久连接,服务器能够主动向客户端推送数据,从而实现真正的实时消息传递。此外,本文还介绍了WebSocket在实际应用中的优势和应用场景,并提供了详细的实现步骤和技术细节。 ... [详细]
  • 字节码开发笔记:深入解析与应用技巧 ... [详细]
  • 计算机图形学基础:辐照度学原理与应用综述
    辐照度(irradiance)是指单位面积上接收到的电磁辐射功率,可视为入射点处的能量密度。在计算机图形学领域,辐照度计算是确定场景中每个位置光照效果的关键步骤。通过对辐照度的精确建模,可以实现更加逼真的光照渲染,提升视觉效果的真实感和沉浸感。本文综述了辐照度的基本原理及其在计算机图形学中的多种应用,探讨了当前研究的热点和技术挑战。 ... [详细]
  • 在学习LVM(逻辑卷管理)技术的过程中,我对MD(多设备)、DM(设备映射器)以及逻辑设备和RAID的实现有了深入的理解。LVM2架构主要由DM主模块及其多个子模块组成,其中linear子模块用于创建线性设备,类似于简单的磁盘分区拼接。此外,还探讨了其他子模块如striped、mirror等在提高性能和数据冗余方面的应用。通过实际操作,我掌握了LVM的基本配置和管理方法,能够灵活应对不同存储需求。 ... [详细]
  • 深入解析 Vue 中的 Axios 请求库
    本文深入探讨了 Vue 中的 Axios 请求库,详细解析了其核心功能与使用方法。Axios 是一个基于 Promise 的 HTTP 客户端,支持浏览器和 Node.js 环境。文章首先介绍了 Axios 的基本概念,随后通过具体示例展示了如何在 Vue 项目中集成和使用 Axios 进行数据请求。无论你是初学者还是有经验的开发者,本文都能为你解决 Vue.js 相关问题提供有价值的参考。 ... [详细]
  • 在使用 iframe 嵌入外部页面时,经常会遇到页面加载不同步的问题。当嵌入的页面响应较慢时,这种异步加载会导致用户体验不佳。本文介绍了如何通过监听 iframe 加载完成的事件来解决这一问题,并提出了针对双滚动条问题的有效解决方案,以提升整体的用户体验和页面加载效率。 ... [详细]
author-avatar
king1994
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有