javascript闭包学习例子

时间:2023-03-09 16:43:43
javascript闭包学习例子

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

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

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

先看几个例子:

 function foo(){
var a = 2; function bar(){
console.log(a);
}
return bar;
}
var baz = foo();
baz(); // 2

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

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

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

 

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

 function foo() {
var num = 2;
function bar() {
alert(++num);
}
bar();
}
foo(); //3
foo(); //3

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

看这个例子:

   function f1(){
    var n=999;
    nAdd=function(){n+=1}
    function f2(){
      alert(n);
    }
    return f2;
  }
  var result=f1();
  result(); //
  nAdd();
  result(); //

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

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

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

看这个例子:

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

 function msg(){
console.log("Message");
}
setTimeout(msg,2000);

两秒后输出:Message

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

 function msg(m){
return function() {
console.log("Message from: " + m);
}
}
setTimeout(msg("setTimeout"),2000);

两秒后输出:Message from: setTimeout

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

 function msg(m){
return function(m) {
console.log("Message from: " + m);
}
}

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

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

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

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

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

 var aLi = document.getElementsByTagName('li');
for (var i = 0; i <= aLi.length; i++) {
aLi[i].onclick = (function(i){
return function(){
alert(i);
};
})(i);
}

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

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

   var aLi = document.getElementsByTagName('li');
for(var i=0;i<aLi.length;i++){
(function(i){
aLi[i].onclick = function(){
alert(i);
}
})(i)
}

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