理解JS闭包——以计数器为例

假如我们需要制作一个计数器,每点击一次就加1。代码写成这样:

var counter = 0;      //把计数器counter设置成全局变量
function add(){
   return counter+=1;
}
add();   //1
add();   //2
add();   //此时counter=3

每执行add()函数一次,相当于执行 counter=counter+1 一次,等于是为counter重新赋值,这样执行过3次add()后,因为counter是全局变量,所以此时counter为3,实现了计数器的功能。但这样有一个问题,即counter暴露出来了,其他函数或者动作也能改变它的值。如:

var counter = 0;
function add(){
   return counter+=1;
}
add();
add();
add();
//  counter为3

counter++;
//counter为4

这样的计数器是不安全也不符合要求的。但是如果将counter设置在一个函数体内,那么因为counter是函数局部变量,每次调用的时候counter都会恢复成初始值。如:

function add(){
   var counter=0;
   counter+=1;
}
add();   //counter为1
add();   //counter为1
add();   //counter为1

所以我们需要的是这么一个变量counter,它在函数每次调用时不要重置,但是它存在于函数内部。

在JavaScript中,所有函数都能访问它们上一层的作用域。所以在父函数里定义子函数,子函数能访问父函数的变量。子函数就相当于闭包。如果把计数器counter定义在父函数内,然后在子函数调用计数器counter,再在父函数外面执行子函数进行计数。那么这个计数器只能通过嵌套函数访问到,并且每次计数都不会重置(因为我们执行的是子函数,只有执行父函数时该计数器才会重置)。

这个思想很好,但是如果我们把代码写成这样:

//例1

var add = function(){
      var counter = 0;
      return function(){
             return(++counter);
      }
};
add();   //counter为1
add();   //counter为1
add();   //counter为1

无论调用add()函数多少次,都返回1,不能实现累加效果。这是为什么呢?

在例1中,add函数的执行顺序为:

1、将counter 设置为0;

2、返回一个函数 function(){return(++counter)}。

所以每次调用add函数将重复1,2两个步骤,相当于依然从重置了counter。

注意:要调用add函数,实现++counter,需要这样操作 :add()()。这是为什么呢?且看下图:

如果只执行add()。那么就将按照1,2的顺序执行,最终的结果就是返回一个函数function(){return(++count)}。

所以要实现++counter,必须得对add()执行一次后的结果(就是函数function(){++count})再次调用,即调用add(),也即add()()。

但是每次调用add()(),执行的顺序就是:

1、将counter 设置为0;

2、返回一个函数 function(){++counter};

3、执行函数function(){++counter}。

每次调用都重置了counter。

结论:对于一个有闭包的函数来说,如果他有一层嵌套(即函数中嵌套一个闭包函数),那么要调用这个函数,需要两个()()。因为闭包中返回的是一个函数,调用时只用一个(),结果就是返回闭包的那个函数,而不是闭包函数的执行结果。而实际上我们需要的是执行闭包的那个函数后的结果。

再看下面这段代码:

//例2

var add = (function(){
      var counter = 0;
      return function(){
             return(++counter);
      }
})();      //这里add已经是执行过后的函数了。即add指定了函数自我调用的返回值
add();   //counter为1
add();   //counter为2
add();   //counter为3

在例2中,变量add指定的是函数自我调用的返回值(指定一个函数并立即执行该函数),即例2中的add是执行了例1中add函数后返回的结果。也就是说,add实际上就是函数function(){++function}。看下图:

第一次调用add(),相当于执行了function(){return (++counter)}一次;

第二次调用add(),相当于又执行了function(){return (++counter)}一次;

又由于function(){return (++counter)}是闭包,引用了其父函数的变量counter,所以在函数调用完毕counter依然存在,没有清零。

而且只在第一次给add赋值时,将counter设置为0。以后每次调用add(),counter都自增一次,没有重置。也就是前文说的,父函数只执行一次,每次调用都只执行了子函数。

时间: 2024-12-22 22:37:34

理解JS闭包——以计数器为例的相关文章

理解js闭包原理

各种专业文献上的"闭包"(closure)定义非常抽象,很难看懂.我的理解是,闭包就是能够读取其他函数内部变量的函数. 由于在Javascript语言中,只有函数内部的子函数才能读取局部变量,因此可以把闭包简单理解成"定义在一个函数内部的函数". 所以,在本质上,闭包就是将函数内部和函数外部连接起来的一座桥梁. 闭包可以用在许多地方.它的最大用处有两个,一个是前面提到的可以读取函数内部的变量,另一个就是让这些变量的值始终保持在内存中. 怎么来理解这句话呢?请看下面的

javascript深入理解js闭包(看了挺多的,感觉这篇比较透彻)

闭包(closure)是Javascript语言的一个难点,也是它的特色,很多高级应用都要依靠闭包实现. 一.变量的作用域 要理解闭包,首先必须理解Javascript特殊的变量作用域. 变量的作用域无非就是两种:全局变量和局部变量. Javascript语言的特殊之处,就在于函数内部可以直接读取全局变量. Js代码 var n=999; function f1(){ alert(n); } f1(); // 999 另一方面,在函数外部自然无法读取函数内的局部变量. Js代码 function

javascript深入理解js闭包

一.变量的作用域 要理解闭包,首先必须理解Javascript特殊的变量作用域. 变量的作用域无非就是两种:全局变量和局部变量. Javascript语言的特殊之处,就在于函数内部可以直接读取全局变量. Js代码 var n=999; function f1(){ alert(n); } f1(); // 999 另一方面,在函数外部自然无法读取函数内的局部变量. Js代码 function f1(){ var n=999; } alert(n); // error 这里有一个地方需要注意,函数

深入理解js闭包

闭包(closure)是Javascript语言的一个难点,也是它的特色,很多高级应用都要依靠闭包实现. 一.变量的作用域 要理解闭包,首先必须理解Javascript特殊的变量作用域. 变量的作用域无非就是两种:全局变量和局部变量. Javascript语言的特殊之处,就在于函数内部可以直接读取全局变量. Js代码 var n=999; function f1(){ alert(n); } f1(); // 999 另一方面,在函数外部自然无法读取函数内的局部变量. Js代码 function

javascript深入理解js闭包(摘自网络)

闭包(closure)是Javascript语言的一个难点,也是它的特色,很多高级应用都要依靠闭包实现. 一.变量的作用域 要理解闭包,首先必须理解Javascript特殊的变量作用域. 变量的作用域无非就是两种:全局变量和局部变量. Javascript语言的特殊之处,就在于函数内部可以直接读取全局变量. Js代码 var n=999; function f1(){ alert(n); } f1(); // 999 另一方面,在函数外部自然无法读取函数内的局部变量. Js代码 function

(转)javascript深入理解js闭包

一.变量的作用域 要理解闭包,首先必须理解Javascript特殊的变量作用域. 变量的作用域无非就是两种:全局变量和局部变量. Javascript语言的特殊之处,就在于函数内部可以直接读取全局变量. Js代码 var n=999; function f1(){ alert(n); } f1(); // 999 另一方面,在函数外部自然无法读取函数内的局部变量. Js代码 function f1(){ var n=999; } alert(n); // error 这里有一个地方需要注意,函数

javascript深入理解js闭包(个人理解,大神勿喷)

一.变量的作用域 要理解闭包,首先必须理解Javascript特殊的变量作用域. 变量的作用域无非就是两种:全局变量和局部变量. Javascript语言的特殊之处,就在于函数内部可以直接读取全局变量. Js代码 var n=999; function f1(){ alert(n); } f1(); // 999 另一方面,在函数外部自然无法读取函数内的局部变量. Js代码 function f1(){ var n=999; } alert(n); // error 这里有一个地方需要注意,函数

javascript深入理解js闭包【手动加精】

http://www.jb51.net/article/24101.htm 闭包(closure)是Javascript语言的一个难点,也是它的特色,很多高级应用都要依靠闭包实现. 一.变量的作用域 要理解闭包,首先必须理解Javascript特殊的变量作用域. 变量的作用域无非就是两种:全局变量和局部变量. Javascript语言的特殊之处,就在于函数内部可以直接读取全局变量. Js代码 var n=999; function f1(){ alert(n); } f1(); // 999 另

深入理解js 闭包

要理解闭包,首先必须理解Javascript特殊的变量作用域. 变量的作用域无非就是两种:全局变量和局部变量. Javascript语言的特殊之处,就在于函数内部可以直接读取全局变量. Js代码 var n=999; function f1(){ alert(n); } f1(); // 999 另一方面,在函数外部自然无法读取函数内的局部变量. Js代码 function f1(){ var n=999; } alert(n); // error 这里有一个地方需要注意,函数内部声明变量的时候