Klesh.Cn

concentrating on knowing more...

理解Javascript的闭包

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

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

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 />");

  输出内容:

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类库的代码:

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回上层调用:

function getLocalVar() {
	var localVar = "I'm local var";
	return localVar;
}
var globalVar = getLocalVar();

  作用域的概念在很多编程语言中都有存在,在Javascript中一样也有,特别的地方就在于Javascript是一种动态语言,它可以定义内嵌函数。当你在一个函数内部定义一个新的函数时,内嵌函数就可以引用该函数的局部变量。:

function OutterFunction() {
	var outterVar;
	function InnerFunction() {
		return outterVar;
	}
}

  当OutterFunction每次被调用时,解释器会为它分配一个栈区,所有的局部变量都会被放到这个栈区(闭包开始),栈区内的局部变量都是相互可见的,而InnerFunction也是局部变量之一,所以当OutterFunction执行完毕退出以后,InnerFunction依然可以访问到其他的局部变量(闭包形包)。要注意的是InnerFunction每次都被重新创建,每次返回都是不同的。换句话说,闭包就是指返回出来的InnerFunction可以访问到OutterFunction的局部变量这种情形

  理解并合理地使用闭包可以使程序更加灵活和优雅。很多Javascript类库都有闭包的应用,所以,如果需要经常和Javascript打交道的话,闭包是无法绕过的概念。

posted on 2007-10-13 12:43  Klesh Wong  阅读(1027)  评论(8编辑  收藏  举报

导航