JavaScript闭包之个人拙见

昨天研究了一下JS的闭包机制,大概整理了一下,记录在此,做个备忘。

首先,JS闭包的理解难点也是其特点在于,它可以把函数体内的局部变量维持住,使得在函数作用域外也能访问到。这和CJava等静态语言的机制是很不一样的。

我们先来一个简单的例子:

1
2
3
4
5
6
7
8
9
var scope = "global scope"; // 全局变量
function checkscope()
{

var scope = "local scope"; // 局部变量
function f() { return scope;} // 在作用域内返回这个值
return f; // 如果返回的是f(),结果会是神马?
}

checkscope()(); // "local scope"

在这个例子,一个明显的特点就是返回值是一个函数对象,而令人费解的是,var scope = "local scope";的作用域应该在函数checkscope()内,而当语句checkscope()()执行时,实际上执行的是checkscope()返回的函数对象,这已经超出了局部变量scope的作用域,而我们却依然取到了它的值,这就是闭包的强大之处了。

当然,也许我们可以认为,我们得到的只是scope的静态快照(static snapshot)。事实真是如此吗,我们一会给个例子来找出这个答案,不过在此之前,我们先讲讲多闭包共享变量,先上例子:

1
2
3
4
5
6
7
8
9
10
11
12
function counter()
{

var n = 0;
return {
count: function() { return n++;},
reset: function() { n = 0;}
};
}
var c = counter();
c.count(); // => 0
c.reset(); // reset()和count()共享了变量状态
c.count(); // => 0: 已经被重置了

在这个例子中,counter()返回了一个“计数器”对象,里面包含两个方法:count()和reset(),这两个方法共享私有变量n。

有了上面那个例子做铺垫,那我们再来解决之前的那个问题,在这个例子中,函数将会创建多个闭包:

1
2
3
4
5
6
7
8
9
10
function constfuncs()
{

var funcs = [];
for(var i = 0; i < 10 ;i++)
funcs[i] = =function() { return i;}
return funcs;
}

var funcs = constfuncs();
funcs[5](); // 结果会是神马

我想大多数盆友会认为结果是5,好吧,我承认我一开始也是这么想的😂。然而结果是10,这大大出乎了我们的预料,其实这个答案也很容易理解,函数返回的多个闭包共享了变量i的状态,而不是各自将其复制一份,也不会对其生成静态快照。

再来讲一个闭包的特殊用途——共享私有状态:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function counter(n)
{
return {
get count() { return n++;},
set count(m) {
if(m > n) n = m;
else throw Error("count can only be set to a larger value");
}
};
}
var c = counter(1000);
c.count // => 1000
c.count // => 1001
c.count = 2000
c.count // => 2000
c.count = 2000 // => Error

这个函数没有声明局部变量而是使用参数n来保存私有状态,属性存取器方法可以访问n,而调用counter()可以指定私有变量的初始值。

我的第一篇技术博客就到此为止了,这篇博客在高亮上貌似遇到了点麻烦…………我也不知道该怎么搞了😰