先来看两段代码,若是你不能完全理解它们的原理,则本文对你还是有一点参考作用的。
首先是我写的一段用来模拟私有成员的代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
function Foobar(parameter) {
var privateVariable = "I'm private Variable";
var privateFunction = function() {
return "I'm privateFunction and privateVariable is : " + privateVariable;
}
this.publicVariable = "I'm public Variable";
this.publicFunction = function() {
document.write("parameter : " + parameter + "<br />");
document.write("privateVariable : " + privateVariable + "<br />");
document.write("privateFunction : " + privateFunction() + "<br />");
document.write("publicVariable : " + this.publicVariable + "<br />");
}
}
var foobar = new Foobar("I'm paramter");
foobar.publicFunction();
document.write("typeof(foobar.privateVariable) : " + typeof(foobar.privateVariable) + "<br />");
document.write("typeof(foobar.privateFunction) : " + typeof(foobar.privateFunction) + "<br />");
document.write("typeof(foobar.publicVariable) : " + typeof(foobar.publicVariable) + "<br />");
document.write("typeof(foobar.publicFunction) : " + typeof(foobar.publicFunction) + "<br />");
|
输出内容:
1
2
3
4
5
6
7
8
|
parameter : I'm paramter
privateVariable : I'm private Variable
privateFunction : I'm privateFunction and privateVariable is : I'm private Variable
publicVariable : I'm public Variable
typeof(foobar.privateVariable) : undefined
typeof(foobar.privateFunction) : undefined
typeof(foobar.publicVariable) : string
typeof(foobar.publicFunction) : function
|
可以看到,privateVariable和privateFunction都被成员的隐藏了起来。再看一段来自dojo类库的代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
var getImgInPositionedDivHtml = (function(){
var buffAr = [
'<div id=”‘,
'', //index 1, DIV ID attribute
'“ style=”position:absolute;top:',
'', //index 3, DIV top position
'px;left:',
'', //index 5, DIV left position
'px;width:',
'', //index 7, DIV width
'px;height:',
'', //index 9, DIV height
'px;overflow:hidden;”><img src=”‘,
'', //index 11, IMG URL
'“ width=”‘,
'', //index 13, IMG width
'“ height=”‘,
'', //index 15, IMG height
'“ alt=”‘,
'', //index 17, IMG alt text
'“></div>'
];
return (function(url, id, width, height, top, left, altText){
buffAr[1] = id;
buffAr[3] = top;
buffAr[5] = left;
buffAr[13] = (buffAr[7] = width);
buffAr[15] = (buffAr[9] = height);
buffAr[11] = url;
buffAr[17] = altText;
return buffAr.join(‘');
}); //:End of inner function expression.
})();
|
这是来自于dojo类库的一段代码,基本 上,getImgInPositionedDivHtml是一个用来创建绝对定位div的html代码。这个div是有固定的模式的,变动的只是具体的一 些属性,所以它用了一个buffAr来承载这个模式,getImgInPositionedDivHtml在接收到具体的属性值(url, id, width, height, top, left, altText),就会把它放到buffAr的相应位置,再返回buffAr的join后的字符串。而无论 getImgInPositionedDivHtml被执行多少次,buffAr只会被创建一次,类似于静态成员的行为。当然,在真正的面向对向语言中, 我们是不能这么做的,因为还要考虑到线程安全的问题,有点扯远了。
这两段代码,都是利用了Javascript特有的闭包来实现各自的效果,什么是闭包呢?
我们知道,变量有作用域的概念,在一个函数体中,使用var声明局部变量只在函数体中能被引用,而在函数外部则是无法访问该变量的。理论上,局 部变量会在函数执行完毕之后被释放,除非它有在其它地方被引用(也很有可能是在脚本被卸载的时候才统一回收的,但这不影响它能否被引用),最容易理解的就 是被return回上层调用:
1
2
3
4
5
|
function getLocalVar() {
var localVar = “I’m local var”;
return localVar;
}
var globalVar = getLocalVar();
|
作用域的概念在很多编程语言中都有存在,在Javascript中一样也有,特别的地方就在于Javascript是一种动态语言,它可以定义内嵌函数。当你在一个函数内部定义一个新的函数时,内嵌函数就可以引用该函数的局部变量。:
1
2
3
4
5
6
|
function OutterFunction() {
var outterVar;
function InnerFunction() {
return outterVar;
}
}
|
当OutterFunction每次被调用时,解释器会为它分配一个栈区,所有的局部变量都会被放到这个栈区(闭包开始),栈区内的局部变量都 是相互可见的,而InnerFunction也是局部变量之一,所以当OutterFunction执行完毕退出以后,InnerFunction依然可 以访问到其他的局部变量(闭包形包)。要注意的是InnerFunction每次都被重新创建,每次返回都是不同的。换句话说,闭包就是指返回出来的InnerFunction可以访问到OutterFunction的局部变量这种情形。
理解并合理地使用闭包可以使程序更加灵活和优雅。很多Javascript类库都有闭包的应用,所以,如果需要经常和Javascript打交道的话,闭包是无法绕过的概念。