先来看两段代码,若是你不能完全理解它们的原理,则本文对你还是有一点参考作用的。

首先是我写的一段用来模拟私有成员的代码:

 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 = Im 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打交道的话,闭包是无法绕过的概念。