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 }

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

原文地址:https://www.cnblogs.com/ooooevan/p/5738427.html