详解js闭包


Posted in Javascript onSeptember 02, 2014

闭包(closure)是Javascript语言的一个难点,也是它的特色,很多高级应用都要依靠闭包实现。

闭包有三个特性:

1.函数嵌套函数
2.函数内部可以引用外部的参数和变量
3.参数和变量不会被垃圾回收机制回收
闭包是指有权访问另一个函数作用域中的变量的函数,创建闭包的最常见的方式就是在一个函数内创建另一个函数,通过另一个函数访问这个函数的局部变量

使用闭包有一个优点,也是它的缺点,就是可以把局部变量驻留在内存中,可以避免使用全局变量。全局变量在每个模块都可调用,这势必将是灾难性的。

所以推荐使用私有的,封装的局部变量。

一般函数执行完毕后,局部活动对象就被销毁,,内存中仅仅保存全局作用域。但闭包的情况不同!

嵌套函数的闭包:

function aaa() { 
     var a = 1; 
     return function(){
      alert(a++)
     }; 
    }     
    var fun = aaa(); 
    fun();// 1 执行后 a++,,然后a还在~ 
    fun();// 2  
    fun = null;//a被回收!!

 
以上输出结果为5;
闭包会使变量始终保存在内存中,如果不当使用会增大内存消耗。

javascript的垃圾回收原理

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

那么使用闭包有什么好处呢?使用闭包的好处是:

1.希望一个变量长期驻扎在内存中
2.避免全局变量的污染
3.私有成员的存在
一、全局变量的累加

<script>
var a = 1;
function abc(){
    a++;
    alert(a);
}
abc();       //2
abc();      //3
</script>

二、局部变量
<script>

function abc(){
    var a = 1;
    a++;
    alert(a);
}
abc();            //2
abc();          //2
</script>

那么怎么才能做到变量a既是局部变量又可以累加呢?

三、局部变量的累加(闭包所能做到的)

<script>
function outer(){
    var x=10;
    return function(){       //函数嵌套函数
        x++;
        alert(x);
    }
}
var y = outer();       //外部函数赋给变量y;
y();         //y函数调用一次,结果为11
y();        //y函数调用第二次,结果为12,实现了累加
</script>

js中的函数声明与函数表达式:
在js中我们可以通过关键字function来声明一个函数:

<script>
function abc(){
    alert(123);
}
abc();
</script>

我们也可以通过一个"()"来将这个声明变成一个表达式:

<script>
(function (){
    alert(123);
})();          //然后通过()直接调用前面的表达式即可,因此函数可以不必写名字;
</script>

四、模块化代码,减少全局变量的污染

<script>
var abc = (function(){   //abc为外部匿名函数的返回值
    var a = 1;
    return function(){
        a++;
        alert(a);
    }
})();
abc();  //2 ;调用一次abc函数,其实是调用里面内部函数的返回值  
abc();  //3
</script>

五、私有成员的存在

<script>
var aaa = (function(){
    var a = 1;
    function bbb(){
        a++;
        alert(a);
    }
    function ccc(){
        a++;
        alert(a);
    }
    return {
        b:bbb,       //json结构
        c:ccc
    }
})();
aaa.b();   //2
aaa.c()   //3
</script>

六、在循环中直接找到对应元素的索引

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
  <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
  <head>
      <meta http-equiv="Content-Type" content="text/html;charset=UTF-8" />
      <title></title>
  <script>
  window.onload = function(){
      var aLi = document.getElementsByTagName('li');
      for (var i=0;i<aLi.length;i++){
          aLi[i].onclick = function(){    //当点击时for循环已经结束
          alert(i);
          };
      }
  }
  </script>

  </head>
  <body>
      <ul>
          <li>123</li>
          <li>456</li>
          <li>789</li>
          <li>010</li>
      </ul>
  </body>
  </html>

七、使用闭包改写上面代码:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

  <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
  <head>
      <meta http-equiv="Content-Type" content="text/html;charset=UTF-8" />
      <title></title>
  <script>
  window.onload = function(){
      var aLi = document.getElementsByTagName('li');
      for (var i=0;i<aLi.length;i++){
          (function(i){
              aLi[i].onclick = function(){
                  alert(i);
              };
          })(i);
      }
      };
  </script>

  </head>
  <body>
      <ul>
          <li>123</li>
          <li>456</li>
          <li>789</li>
      </ul>
  </body>
  </html>
Javascript 相关文章推荐
为Yahoo! UI Extensions Grid增加内置的可编辑器
Mar 10 Javascript
基于javascipt-dom编程 table对象的使用
Apr 22 Javascript
JavaScript子类用Object.getPrototypeOf去调用父类方法解析
Dec 05 Javascript
JavaScript中对循环语句的优化技巧深入探讨
Jun 06 Javascript
JS实现在网页中弹出一个输入框的方法
Mar 03 Javascript
介绍JavaScript的一个微型模版
Jun 24 Javascript
JS实现的鼠标跟随代码(卡通手型点击效果)
Oct 26 Javascript
Bootstrap 附加导航(Affix)插件实例详解
Jun 01 Javascript
通过实例了解js函数中参数的传递
Jun 15 Javascript
JavaScript创建、读取和删除cookie
Sep 03 Javascript
如何阻止小程序遮罩层下方图层滚动
Sep 05 Javascript
JavaScript 俄罗斯方块游戏实现方法与代码解释
Apr 08 Javascript
jquery delay()介绍及使用指南
Sep 02 #Javascript
使用jquery实现放大镜效果
Sep 02 #Javascript
javascript初学者常用技巧
Sep 02 #Javascript
js/jquery判断浏览器的方法小结
Sep 02 #Javascript
Iframe实现跨浏览器自适应高度解决方法
Sep 02 #Javascript
jQuery级联操作绑定事件实例
Sep 02 #Javascript
jquery和css3实现的炫酷时尚的菜单导航
Sep 01 #Javascript
You might like
无JS,完全php面向过程数据分页实现代码
2012/08/27 PHP
php检测用户是否用手机(Mobile)访问网站的类
2014/01/09 PHP
PHP解耦的三重境界(浅谈服务容器)
2017/03/13 PHP
PHP实现求连续子数组最大和问题2种解决方法
2017/12/26 PHP
PHP程序员学习使用Swoole的理由
2018/06/24 PHP
laravel5使用freetds连接sql server的方法
2018/12/07 PHP
Windows上php5.6操作mongodb数据库示例【配置、连接、获取实例】
2019/02/13 PHP
PHP使用DOM对XML解析处理操作示例
2019/07/04 PHP
ASP.NET jQuery 实例10 动态修改hyperlink的URL值
2012/02/03 Javascript
通过jQuery源码学习javascript(一)
2012/12/27 Javascript
ExtJs默认的字体大小改变的几种方法(自己整理)
2013/04/18 Javascript
动态改变div的z-index属性的简单实例
2013/08/08 Javascript
JavaScript中创建对象和继承示例解读
2014/02/12 Javascript
JavaScript程序员应该知道的45个实用技巧
2014/03/04 Javascript
在JavaScript中使用对数Math.log()方法的教程
2015/06/15 Javascript
JS表格组件神器bootstrap table详解(基础版)
2015/12/08 Javascript
angularjs封装bootstrap时间插件datetimepicker
2016/06/20 Javascript
javascript编程实现栈的方法详解【经典数据结构】
2017/04/11 Javascript
jQuery取得元素标签名称小结(附代码)
2017/08/16 jQuery
微信小程序自定义键盘 内部虚拟支付
2018/12/20 Javascript
Vue表单提交点击事件只允许点击一次的实例
2020/10/23 Javascript
如何利用nodejs实现命令行游戏
2020/11/24 NodeJs
Python上传package到Pypi(代码简单)
2016/02/06 Python
详解Python中表达式i += x与i = i + x是否等价
2017/02/08 Python
详解Python3.6的py文件打包生成exe
2018/07/13 Python
关于Python Tkinter Button控件command传参问题的解决方式
2020/03/04 Python
django实现后台显示媒体文件
2020/04/07 Python
Tommy Hilfiger澳洲官网:美国高端休闲领导品牌
2020/12/16 全球购物
生产经理的自我评价分享
2013/11/07 职场文书
人大调研汇报材料
2014/08/14 职场文书
单方离婚协议书范本(2014版)
2014/09/30 职场文书
初婚未育证明样本
2015/06/18 职场文书
党员学习中国梦心得体会
2016/01/05 职场文书
解决Golang time.Parse和time.Format的时区问题
2021/04/29 Golang
梳理总结Python开发中需要摒弃的18个坏习惯
2022/01/22 Python
Apache Hudi 加速传统的批处理模式
2022/04/24 Servers