首页 > 代码库 > JS基础——闭包

JS基础——闭包

有关JS中闭包的理解和使用。

一、简介

       子函数可以使用父函数中的局部变量,这种行为就叫做闭包。通常指,有权访问另一个函数作用域中的变量的函数。创建时,通常在一个函数中创建另一个函数,通过另一个函数访问这个函数的局部变量。

function box() {
  var user = 'Lee';
  return function () { //通过匿名函数返回 box()局部变量
  return user;
  };
}
alert(box()());
这里通过一个匿名函数来访问父函数中的user变量,并且返回这个变量的值,那么在外部我们可以通过直接调用来box()来访问匿名函数。

在这里看似没什么作用,有点儿画蛇添足。那么为什么还要使用闭包呢?

当然,它也有自己的优点:通过闭包实现变量永驻内存,避免全局变量实现累加

 二、利用闭包实现累加

     传统方式:声明一个全局变量实现累加

		var age=100; //全局变量的声明
		function box(){
			age++;
		}
		box();
		alert(age);
通过这种方式,如果在大型软件开发中,全局变量会造成很多不可想象的麻烦,通常我们应该尽量减少全局变量的使用。但是,这里如果使用局部变量的声明方式,又不能实现累加。

    局部变量方式:

function box(){		var age=100;
			age++;
			return age;
		 }
		 
		 alert(box());  //需要多次调用box方法来进行,每次执行都会对age进行重新初始化始终为101
那么如何避免局部变量每次的初始化,这里就用闭包来解决。

利用闭包,变量永驻内存,实现累加:

		function box(){
			var age=100;   //box中的局部变量
			return function(){ //匿名函数
				age++;    
    				return age;
			}
  		}
		 var b=box();  
		 alert(b());  //这里调用多次box函数后可实现累加,内存中保留有age变量的值
		 alert(b());
通过上面这种闭包的形式可以实现累加,但是需要调用多次函数,我们可以利用循环来改善这一现象。

 三、循环中的闭包

闭包在循环中的应用可利用下面这些方法来达到同样的效果

    1、匿名函数返回一个数组

function box(){
	var arr=[];
	for (var i=0;i<5;i++){
		arr[i]=function(){
  		return i;
		 }
	 }
	return arr;  //返回一个数组
}
for (i=0;i<5;i++)  //连续实现循环输出
{
	alert(box()[i]()); //结果为5个5
}
注意:通过box()返回一个数组,那么如果在下面输出循环中若执行alert(box()[i])时,那么会执行循环中的函数即,打印出5个匿名函数function(){return i} ,所以,这里我们要注意加上()来执行循环中的匿名函数,才能真正输出数字。那么为什么为5个5呢?

       原因:在每次输出循环时,我们都会执行box()函数,而每次执行时,其实,box函数已经执行完毕,即其实,每次执行输出循环中的一次,box中for循环就执行了5次,即执行到i++=5,而每次循环arr[i]=5,因此每次输出循环结果都为5.其实,这里输出循环中每次输出的都是box函数for循环了5次以后的结果5,而box内部每次循环时,因匿名函数未自我执行,结果均为匿名函数的函数体。只有到第五次,结果才为5。

问题出现在哪里呢?如果在每次循环结束时,匿名函数可以自我执行,那么每次循环完成后,就会返回arr,数组中就会有5个元素分别为0,1,2,3,4,那么在接下来的循环输出时,就可以将这5个元素依次输出了。具体解决方案详见2.直接传参自我执行。

    2、直接传参自我执行

function box(){
	var arr=[];
	for(var i=0;i<5;i++){
		arr[i]=(function (num){
			return num;
		})(i); //通过直接传参自我执行实现循环挨个输出
	}
	return arr;  //自我执行后,每次循环都会返回arr
}
var b=box();
for(var i=0;i<5;i++){
	alert(b[i]);//这里直接b[i]即可,不用再执行内部的匿名函数了
}
这里利用的是通过匿名函数自我传参的方式,实现循环,其实整体上和第一种方式是一样的,只是一个参数执行的区别。

三、循环中返回匿名函数

function box(){
	var arr=[];
	for(var i=0;i<5;i++){
	arr[i]=(function (num){
	//num在这里
		return function(){ //返回一个闭包
			return num;
		}
	    })(i); //把i传给num
      }
	return arr;
}
 var b=box();
 for( var i=0;i<5;i++){ 
	alert(b[i]());
 }

        第三种通过返回一个闭包,这种方式如果利用JS进行逐句调试会发现,它的执行顺序和结果与第一种是一样的。即先执行box()返回5个function,可是最后执行完输出循环后,结果显示为0,1,2,3,4这里就是运用了闭包可以使变量永驻内存的原理,在执行box()循环时,它将变量i保存了起来,而在输出时,直接按顺序输出即可。

      小结:通过闭包来实现变量存储在内存中,在很多应用中确实很方便,但是由于它占据了内存,所以在一些用到大量变量的程序中,会影响到程序执行的性能,所以闭包还是要慎用!



JS基础——闭包