码迷,mamicode.com
首页 > 编程语言 > 详细

javascript闭包

时间:2014-08-04 13:57:27      阅读:308      评论:0      收藏:0      [点我收藏+]

标签:style   blog   http   java   使用   strong   io   for   

闭包是一个什么概念呢?先来看下面一段代码:

bubuko.com,布布扣
<html>
<head>
<title>js闭包</title>
<script type="text/javascript">
window.onload =    function(){
    var divs=document.getElementsByTagName("div");
    for(var i=0; i<divs.length; i++){
         divs[i].onclick=function(){
             alert(i);    //每次都输出5
        }
    }
}
</script>
</head>
<body>
<div style=" width:100px; height:100px"></div>
<div style=" width:100px; height:100px"></div>
<div style=" width:100px; height:100px"></div>
<div style=" width:100px; height:100px"></div>
<div style=" width:100px; height:100px"></div>
</body>
</html
bubuko.com,布布扣

  如果要改为弹出正确的序号(从0开始)则js要改为如下这样:

bubuko.com,布布扣
<script type="text/javascript">
function A(){
    var divs=document.getElementsByTagName("div");
   for(var i=0; i<divs.length; i++){
      (function(n){      //实际的思路其实是,对于每个onclick的内部函数,都有了一个父变量n。并且内存不能销毁
        divs[i].onclick=function(){
          alert(n);
     }
    })(i)
 }
}

window.onload =    function()
{
    A();
}
</script>
bubuko.com,布布扣

  这据说是闭包这个牛B词的实现。

  其实,他写的太复杂了,实际上相当于这样写,而实际上在真正的开发中,下面的代码风格也是比较好的。

bubuko.com,布布扣
<script type="text/javascript">
var divs;
function A(){
    divs = document.getElementsByTagName("div");
    for(var i=0; i<divs.length; i++){
       bindclick(i)
    }
}

function bindclick(i)          //参数相当于内部变量,每调用一次都有一个独立的内部变量
{
    divs[i].onclick = function(){
        alert(i);
    }
}

window.onload = function()
{
    A();
}
</script>
bubuko.com,布布扣

  哈,这样就清晰多了。效果一样。

  下面再给出一个无论点击哪个先哪个后都弹出1 2 3 4 5

bubuko.com,布布扣
<script type="text/javascript">
function A(){
    var divs=document.getElementsByTagName("div");
    var j = 0;
    for(var i=0; i<divs.length; i++){
        divs[i].onclick=function(){
          alert(j);
          j++;
     }
 }
}

window.onload =    function()
{
    A();
}
</script>
bubuko.com,布布扣

  要说明这个原因,首先要理解了内部函数的概念!

一、什么是内部函数

  一个示例说明:

function A(){
    function B(){            //B就是一个内部函数
        alert("你好!");
    }
}

  由于函数B在函数A的内部,因此B函数在函数A内有效,但是在外部调用时无效的,如:

bubuko.com,布布扣
<script type="text/javascript">
window.onload = B();  //外部调用无效

function A(){
    alert("你好");
    function B(){            //B就是一个内部函数
        alert("你好!");
    }
}
</script>
bubuko.com,布布扣

  在js报如下错误:

  bubuko.com,布布扣

  但是在内部调用又是正确的:

bubuko.com,布布扣
<script type="text/javascript">
window.onload = A();

function A(){
    function B(){
        alert("你好!");
    }
    B();        //内部调用A()是正确的
}
</script>
bubuko.com,布布扣

  不能在外部调用内部函数,这我很不爽,有没有办法硬是要在外部调用内部的函数呢?答案是有的:

  方法一、全局变量绑定函数

bubuko.com,布布扣
<script type="text/javascript">
window.onload =    A();

function A(){
    function B(){
        alert("你好!");
    }
    global = B;
}
global();    //全局变量来调用内部函数
</script>
bubuko.com,布布扣

  虽然可以调用B()了,但是必须使用全局变量global,直接在外部调用B()一样出错。

  方法二、通过返回值调用函数

bubuko.com,布布扣
<script type="text/javascript">
function A(){
    function B(){
        alert("你好!");
    }
    return B;
}

window.onload =    function(){
    var fn = A();    //返回内部函数的引用
    fn();    //调用引用
}
</script>
bubuko.com,布布扣

  javascript运行时需要跟踪引用这个内部函数的所有变量,直到最后一个变量废弃,javascript垃圾收集器才能释放内部函数的内存空间。也就是说,只要存在调用内部函数的可能,javascript就要保留被引用的函数。

  2014-04-14,这里要特别说明一下:

bubuko.com,布布扣
    function f1()
    {
        r = 10;
    }

    function f1()
    {
        var r = 10;
    }
bubuko.com,布布扣

  以上两个方法是不同的,加了var就是局部变量,不加var就是全局变量。

二、内部函数与闭包的关系

  闭包是指有权访问另一个函数作用域的变量(包括变量与函数等等)的函数,创建闭包的常见方式则是在一个函数内部创建另一个函数。

  变量的作用域

bubuko.com,布布扣
<script type="text/javascript">
function A(){
   function B(){
      var i = 0;    //B的内部变量
      i++;
      alert(i);
    }
  return B;
}

window.onload =    function(){
    var fn = A();
    fn();            //弹出1
    fn();            //弹出1
    var fn2 = A();
    fn2();            //弹出1
    fn2();            //弹出1
}
</script>
bubuko.com,布布扣

  因为每次通过引用调用B()函数,都会创建一个 i 变量,并且++后值为1。

bubuko.com,布布扣
<script type="text/javascript">
var i = 0;    //全局变量

function A(){
   function B(){
      i++;
      alert(i);
    }
  return B;
}

window.onload = function(){
    var fn = A();
    fn();            //弹出1
    fn();            //弹出2
    var fn2 = A();
    fn2();            //弹出3
    fn2();            //弹出4
}
</script>
bubuko.com,布布扣

  因为调用的是全局变量i,所以每次++,+的都是同一个。

  如果调用的是父函数的局部变量,也类似:

bubuko.com,布布扣
<script type="text/javascript">
function A(){
    var i = 0;    //父函数的局部变量
   function B(){
      i++;
      alert(i);
    }
  return B;
}

window.onload =    function(){
    var fn = A();
    fn();            //弹出1
    fn();            //弹出2
    var fn2 = A();
    fn2();            //弹出1
    fn2();            //弹出2
}
</script>
bubuko.com,布布扣

  因为是变量时父函数的变量。因此,调用A()的时候都var i = 0;所以是从0开始。

  说白了闭包就是用些什么乱七八糟的方法去访问函数内部的变量或函数。

三、闭包的作用

  闭包有两个作用:

  1. 函数外部访问函数内部的函数或变量;
  2. 常驻内存;

  来看示例:

bubuko.com,布布扣
  function f1(){
    var n=999;
    nAdd=function()
        {
            n += 1;
        }
    function f2(){
      alert(n);
    }
    return f2;
  }
  var result=f1();
  result(); // 999
  nAdd();
  result(); // 1000
bubuko.com,布布扣

  result实际上就是闭包f2函数。它一共运行了两次,第一次的值是999,第二次的值是1000。这证明了,函数f1中的局部变量n一直保存在内存中,并没有在f1调用后被自动清除。

  为什么会这样呢?原因就在于f1是f2的父函数,而f2被赋给了一个全局变量(result),这导致f2始终在内存中,而f2的存在依赖于f1,因此f1也始终在内存中,不会在调用结束后,被垃圾回收机制(garbage collection)回收。

javascript闭包,布布扣,bubuko.com

javascript闭包

标签:style   blog   http   java   使用   strong   io   for   

原文地址:http://www.cnblogs.com/mingxuantongxue/p/3889707.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!