详解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 相关文章推荐
imgAreaSelect 中文文档帮助说明
Oct 08 Javascript
js鼠标点击事件在各个浏览器中的写法及Event对象属性介绍
Jan 24 Javascript
模拟一个类似百度google的模糊搜索下拉列表
Apr 15 Javascript
关闭时刷新父窗口两种方法
May 07 Javascript
实例代码详解javascript实现窗口抖动及qq窗口抖动
Jan 04 Javascript
深入理解jquery跨域请求方法
May 18 Javascript
JavaScript中的Object对象学习教程
May 20 Javascript
关于javascript事件响应的基础语法总结(必看篇)
Dec 26 Javascript
jQuery实现的简单排序功能示例【冒泡排序】
Jan 13 Javascript
vue.js 2.0实现简单分页效果
Jul 29 Javascript
Jquery 动态添加元素并添加点击事件实现过程解析
Oct 12 jQuery
vue-cli在 history模式下的配置详解
Nov 26 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
咖啡与牛奶
2021/03/03 冲泡冲煮
PHP setcookie指定domain参数后,在IE下设置cookie失效的解决方法
2011/09/09 PHP
PHP中数组的三种排序方法分享
2012/05/07 PHP
如何使用“PHP” 彩蛋进行敏感信息获取
2013/08/07 PHP
Swoole-1.7.22 版本已发布,修复PHP7相关问题
2015/12/31 PHP
php实现微信支付之企业付款
2018/05/30 PHP
Laravel使用RabbitMQ的方法示例
2019/06/18 PHP
jQuery与ExtJS之选择实例分析
2010/08/19 Javascript
Javascript 遮罩层和加载效果代码
2013/08/01 Javascript
浅谈JavaScript函数参数的可修改性问题
2013/12/05 Javascript
jQuery数据类型小结(14个)
2016/01/08 Javascript
基于JS+Canves实现点击按钮水波纹效果
2016/09/15 Javascript
基于JS实现翻书效果的页面切换样式
2017/02/16 Javascript
微信小程序 跳转传递数据的实例
2017/07/06 Javascript
JS路由跳转的简单实现代码
2017/09/21 Javascript
使用vs code开发Nodejs程序的使用方法
2017/09/21 NodeJs
Vue项目添加动态浏览器头部title的方法
2018/07/11 Javascript
js中实例与对象的区别讲解
2019/01/21 Javascript
微信小程序页面间传值与页面取值操作实例分析
2019/04/30 Javascript
微信小程序位置授权处理方法
2019/06/13 Javascript
基于vue 动态菜单 刷新空白问题的解决
2020/08/06 Javascript
js前端传json后台接收‘‘被转为quot的问题解决
2020/11/12 Javascript
Python linecache.getline()读取文件中特定一行的脚本
2008/09/06 Python
SublimeText 2编译python出错的解决方法(The system cannot find the file specified)
2013/11/27 Python
Python实现队列的方法
2015/05/26 Python
Python模拟浏览器上传文件脚本的方法(Multipart/form-data格式)
2018/10/22 Python
详解python方法之绑定方法与非绑定方法
2020/08/17 Python
美国领先的男士和女士内衣购物网站:Freshpair
2019/02/25 全球购物
美国NBA官方商店:NBA Store
2019/04/12 全球购物
环境保护标语
2014/06/20 职场文书
幼儿生日活动方案
2014/08/27 职场文书
高中毕业典礼演讲稿
2014/09/09 职场文书
2015年基层党建工作汇报材料
2015/06/25 职场文书
Goland使用Go Modules创建/管理项目的操作
2021/05/06 Golang
分享Python异步爬取知乎热榜
2022/04/12 Python
详细介绍Next.js脚手架完整搭建封装
2022/04/26 Javascript