详解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 相关文章推荐
小议Function.apply()之二------利用Apply的参数数组化来提高 JavaScript程序性能
Nov 30 Javascript
javascript新手语法小结
Jun 15 Javascript
javascript 装载iframe子页面,自适应高度
Mar 20 Javascript
js弹窗代码 可以指定弹出间隔
Jul 03 Javascript
js css后面所带参数含义介绍
Aug 18 Javascript
javascript表单验证和Window详解
Dec 11 Javascript
BootStrap 可编辑表Table格
Nov 24 Javascript
JavaScript 数组去重并统计重复元素出现的次数实例
Dec 14 Javascript
vue 标签属性数据绑定和拼接的实现方法
May 17 Javascript
JS数组实现分类统计实例代码
Sep 30 Javascript
解决Vue调用springboot接口403跨域问题
Sep 02 Javascript
Vue中Table组件行内右键菜单实现方法(基于 vue + AntDesign)
Nov 21 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
PHP代码审核的详细介绍
2013/06/13 PHP
PHP-Java-Bridge使用笔记
2014/09/22 PHP
一段效率很高的for循环语句使用方法
2007/08/13 Javascript
几个常用的JavaScript字符串处理函数 - split()、join()、substring()和indexOf()
2009/06/02 Javascript
JavaScript高级程序设计 阅读笔记(四) ECMAScript中的类型转换
2012/02/27 Javascript
jQuery mobile 移动web(6)
2015/12/20 Javascript
基于Bootstrap3表格插件和分页插件实例详解
2016/05/17 Javascript
Javascript之Math对象详解
2016/06/07 Javascript
用JS实现图片轮播效果代码(一)
2016/06/26 Javascript
Angularjs 创建可复用组件实例代码
2016/10/09 Javascript
JS实现滑动门效果的方法详解
2016/12/19 Javascript
Vue数据驱动模拟实现1
2017/01/11 Javascript
使用use注册Vue全局组件和全局指令的方法
2018/03/08 Javascript
微信小程序表单弹窗实例
2018/07/19 Javascript
vue中组件通信的八种方式(值得收藏!)
2019/08/09 Javascript
keep-alive不能缓存多层级路由菜单问题解决
2020/03/10 Javascript
python 生成不重复的随机数的代码
2011/05/15 Python
在Django框架中设置语言偏好的教程
2015/07/27 Python
Python二叉树的镜像转换实现方法示例
2019/03/06 Python
Python之NumPy(axis=0 与axis=1)区分详解
2019/05/27 Python
在python里创建一个任务(Task)实例
2020/04/25 Python
Django在Model保存前记录日志实例
2020/05/14 Python
Python3.9 beta2版本发布了,看看这7个新的PEP都是什么
2020/06/10 Python
基于Python实现简单学生管理系统
2020/07/24 Python
PyCharm 2020.2 安装详细教程
2020/09/25 Python
python如何实时获取tcpdump输出
2020/09/16 Python
详解Scrapy Redis入门实战
2020/11/18 Python
python+selenium+chrome实现淘宝购物车秒杀自动结算
2021/01/07 Python
施华洛世奇中国官网:SWAROVSKI中国
2020/06/16 全球购物
毕业生动漫设计求职信
2013/10/11 职场文书
售房协议书
2014/08/19 职场文书
公证委托书标准格式
2014/09/11 职场文书
批评与自我批评范文
2014/10/15 职场文书
2014年发展党员工作总结
2014/11/12 职场文书
首都博物馆观后感
2015/06/05 职场文书
2015年政教主任工作总结
2015/07/23 职场文书