一、引入
我们假如想实现一个计数器的功能,我们可能会像下面这样写。
var count = 0;
function increase(){
return ++count ;
}
这样从功能角度上看是可以的,但是从设计角度看是不优雅的,很明显的一个问题就是向外暴露了内部成员,外部能够直接操作它,可能会导致计数错误。而且还会污染全局命名空间。
在像C/C++、这种语言中,我们可以用局部静态变量来实现。如下
unsigned int increase()
{
static unsigned int count = 0;
return ++count;
}
在JavaScript中,是没有静态变量这个概念的,像下面一样。
function add(){
static var count = 0;
return ++count;
}
这样使用会报错。
那么有没有一种可行的方式,能够像使用静态变量一样呢?答案就是闭包。
二、闭包
在Javascript中有嵌套函数这个概念,我们可以用嵌套函数来实现局部静态变量的功能。那么什么是嵌套函数?
1.嵌套函数
字面上意思,我们可以在函数中嵌套函数。如下所示
function host() {
var count = 0;
var increase = function () {
return ++count;
};
console.log(increase());
console.log(increase());
console.log(increase());
}
在控制台调用func()得到如下结果:
可以发现,count这个函数中的变量可以被它所在函数的下的嵌套函数中使用。那么这有什么用呢?我们可以这样想,如果我们可以在外部(函数func()的外部)调用increase()这个函数,那么我们是不是就可以认为count这个变量相当于一个静态局部变量,从而可以实现计数的功能呢?那么问题来了,怎么在外部使用func()函数内部的嵌套函数呢?答案是我们可以使用对象引用。让宿主函数(func())返回一个函数引用。我们编写如下代码测试:
function host(){
var count = 0;
var increase = function () {
return ++count;
};
return increase;
}
var add = host();
console.log(add());
console.log(add());
console.log(add());
我们使用匿名函数简写
var add = function () {
var count = 0;
var increase = function () {
return ++count;
};
return increase;
}
console.log(add());
console.log(add());
console.log(add());
可以发现返回了函数的引用,让我们在修改一下代码
var add = function () {
var count = 0;
var increase = function () {
return ++count;
};
return increase;
}
console.log(add()());//注意多加了个括号
console.log(add()());
console.log(add()());
可以发现并没有实现我们想要的效果,原因出在哪里呢?
分析可以发现,每次我们调用add()的时候,返回的都是不同的increase实例,因此,我们需要返回同一个实例。我们可以这么做
var add = function () {
var count = 0;
var increase = function () {
return ++count;
};
return increase;
}
add = add();
console.log(add());//注意去掉了括号
console.log(add());
console.log(add());
也可以这么做
var add = function () {
var count = 0;
var increase = function () {
return ++count;
};
return increase;
}()
//add = add();
console.log(add());//注意去掉了括号
console.log(add());
console.log(add());