理解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 阅读(1028) 评论(8) 编辑 收藏 举报