zoukankan      html  css  js  c++  java
  • javascript闭包学习例子

    javascript中的闭包个很让人头疼的概念。总结一下

    闭包是指有权访问一个函数作用域中的变量的函数。创建闭包最常见的方式,是在一个函数内部创建另一个函数,用return返回出去。

    使用闭包可能造成内存占用不足,尽量少使用。

    先看几个例子:

     1 function foo(){
     2     var a = 2;
     3 
     4     function bar(){
     5         console.log(a);
     6     }
     7     return bar;
     8 }
     9 var baz = foo();
    10 baz();  // 2

    bar函数就是一个闭包。调用foo()函数时,得到的是bar函数,赋值给baz。此时,baz就指向内部的bar函数。再调用baz函数,就是调用了内部的bar函数了。

    1  function foo() {
    2      var num = 2;
    3      function bar() {
    4          alert(++num);
    5      }
    6      return bar;
    7  }
    8  var baz = foo();
    9 baz(); //3
    10 baz(); //4

     这和上面的区别是,内部函数变成自加函数,就能说明一些东西了。两次调用,发现它自增,而不是输出相同的数字3,说明了baz函数执行后,num对象没有被销毁,还保存在内存中。

     

     如果没有闭包,那么foo函数执行完后,num对象就要被销毁,但因为闭包的存在,bar函数要访问num对象,所以要把bar函数需要的资源(foo函数)保存在内存中,使其不被销毁。所以输出的是 3 和 4

     1 function foo() {
     2       var num = 2;
     3       function bar() {
     4           alert(++num);
     5       }
     6        bar();
     7   }
     8    foo();  //3
     9    foo();  //3

     如果变成这样,那就没有闭包了(return没了)。无论调用几次都输出3,因为函数运行后就被销毁了,不会保存。

    看这个例子:

     1   function f1(){
     2     var n=999;
     3     nAdd=function(){n+=1}
     4     function f2(){
     5       alert(n);
     6     }
     7     return f2;
     8   }
     9   var result=f1();
    10   result(); // 999
    11   nAdd();
    12   result(); // 1000

    要说明的是,nAdd()为什么能在外面调用?有两点

    1、没有用var ,是一个全局对象,但单有这个还不够。也不能直接在外面调用

    2、f1函数必须先执行才能调用nAdd函数,调用了函数就有了闭包,外面就可以访问里面的全局对象或全局方法了。

     看这个例子:

    有个全局函数叫setTimeout,可以这样使用:

    1 function msg(){
    2 console.log("Message");
    3 }
    4 setTimeout(msg,2000);

    两秒后输出:Message

    下面我们想给msg传递参数,需要让msg返回一个函数给setTimeout使用,如下:

    1 function msg(m){
    2 return function() {
    3 console.log("Message from: " + m);
    4 }
    5 }
    6 setTimeout(msg("setTimeout"),2000);

    两秒后输出:Message from: setTimeout

    上面那个是正确版本,msg的参数t作为闭包的一部分绑定给了返回的函数,如果我们这样定义的话就是错误的:

    1 function msg(m){
    2 return function(m) {
    3 console.log("Message from: " + m);
    4 }
    5 }

    因为返回了一个带参数“m”的函数,会在setTimeout执行的时候在当前上下文中查找一个叫“m”的变量,而并没有此变量,故得到一个非预期的输出如下:Message from: undefined

     闭包可以解决一个最常见的循环调用的例子:一个ul,点击每个li,弹出它的索引值。

    1 var aLi = document.getElementsByTagName('li'); //假设有6个li
    2 for(var i = 0; i < aLi.length; i++){
    3   aLi[i].onclick = function(){
    4     alert(i);
    5   }
    6 }

     看起来好像对了,其实结果是:无论你点击哪一个li,弹出的都是6。这是因为for里面的匿名函数没有保存起来,加载网页的时候执行了,循环结束了。点击时,会去寻找变量i,这时循环结束,i是6。

    用闭包可以把它保存起来:

    1 var aLi = document.getElementsByTagName('li');    
    2 for (var i = 0; i <= aLi.length; i++) {  
    3   aLi[i].onclick = (function(i){  
    4          return function(){ 
    5          alert(i);  
    6      };  
    7 })(i);    
    8 }

    当点击li时就是调用了闭包函数onclick,使得外部i变量不被销毁,达到目的。

     这样也可以解决,通过闭包机制模仿块级作用域

    1   var aLi = document.getElementsByTagName('li');        
    2      for(var i=0;i<aLi.length;i++){
    3        (function(i){
    4          aLi[i].onclick = function(){
    5             alert(i);
    6         }
    7 })(i)
    8 }

     以上为学习总结,如有错误,望指正

  • 相关阅读:
    HtmlEncode 和 HtmlDecode
    Visual Studio .Net 的一些小技巧(2)
    Array和ArrayList的区别
    c#中 ?? 是什么意思?
    带有图片预览功能的上传表单 上传预览
    Js实现Repeater全选/反选 功能 终极解决方案
    处理URL重写后postback重写失效的问题 .browser文件
    在TreeView中使用CheckBox(c#)
    SQL操作全集
    智能仓库管理系统方案(一)
  • 原文地址:https://www.cnblogs.com/ooooevan/p/5738427.html
Copyright © 2011-2022 走看看