mysql,Linux,HighPerformance,ruby on Rails

2010年3月15日星期一

如何理解javascript Closures

首先,我非Javascript专家也非Web开发的高手,仅仅是想掌握Javascript,所以遇到了这个
Closures,对我来说,如何用最质朴的语言描述快速理解掌握它是这篇博文写下去的动力。

以下就是我的理解,欢迎交流twitter: @xds2000
Javascript场景:
这里指的是ECMA 262第三版,对于Javascript来说,万物都是对象,function也是。

起步:
一个对象肯定有属性,对于javascript来说,对象除了属性,还有prototype,是什么,也是
对象,这个prototype也会有prototype,这样就形成一个属性链。两类,一类是属性,一类是
prototype。英文中叫prototype chain,这个chain的搜索路径会按父子关系向上查找,一直
到发现null prototype才会结束。那么在javascript中谁有null prototype呢,对,Object.prototype的
prototype,再细下来就是
Object -> prototype -> null prototype
也就是说Object的prototype非null,而是Object的prototype的prototype是一个null prototype.
语言描述起来会很傻,但就是这样。我是感觉这样理解更清晰多了。
对于对象属性,我们只关心赋值和读取两个操作。
对于赋值,没什么需要注意的。主要还是看读取。读取一个值,它(javascript interpreter)的行为
是先从对象实例找属性,没有再找其prototype chain,注意返回值是第一个找到的,即最近的
属性。因为对象是可以继承的,你别忘了。
下一步说scope
说起来我感觉挺麻烦,来段代码分析让你更清楚:
var y = {x:5}; // 创建了一个对象y,全局
function exampleFuncWith(){
    var z;

    with(y){

        z = function(){
            ... // inner function expression body;
        }
    }
    ...
}

//外面执行
exampleFuncWith();


上面这段怎么理解,这样,y是全局对象,exampleFuncWith是函数对象,被创建的时间,会
创建一个[[scope]]属性,是一个list或者link。干嘛用的,当然是把其对应的上下文中的对象都
创建引用,这样就形成一个chain了。
这里z = function() {...}是一个内部的function,它的scope是在with这段里,但关键是有一个y,
所以函数体被执行后会在y这个对象的[[scope]](是属性,你在程序界面是访问不了的,可理解为list和link)中创建一个内部函数引用。

铺垫那么多,这回说重点,什么是Closures呢,看这里:
function exampleClosureForm(arg1, arg2){
    var localVar = 8;
    function exampleReturned(innerArg){
        return ((arg1 + arg2)/(innerArg + localVar));
    }
    /* return a reference to the inner function defined as -
       exampleReturned -:-
    */
    return exampleReturned;
}

var globalVar = exampleClosureForm(2, 4);
javascript closures就是说返回一个函数和它的函数体上下文,也就是让另外的变量当内部函数的引用,也可以把这个引用赋值给另一个函数。这样形成一个环。你如果还是没有理解,可这样看外面变量或函数->外函数体->内函数体->外面变量或函数,这样不就是一个循环体嘛。但这些表面的不是关键,关键是我们如何理解内部函数是如何被调用的。我现在不说你肯定还是不能理解Closure的用处何在。还要看上面的代码,这段代码我们如何调用呢,这样走 globalVar(2),在解释到这个,首先看它的[[scope]] chain,这个chain中头一个就是exampleRetruned,为什么,因为是return的。别理解从 exampleClosureForm(2,4)了。这才是javascript的执行关键。因为我这里有一个2,所以内部函数的引用globalVar就是exampleReturned,你赋值一个2,相当于赋值给了exampleReturned的innerArg参数了。这就是Clores的关键精华。那最后你肯定会问Closures能干什么?可能我说你想怎么干就怎么干,你会鄙视我的无知态度。但事实上你只能在实践中就好比拿着锤子你不打几个钉子还是不会知道这锤子好不好用一样。就这样,以上理解是对参考1链接的读后心得,如有差错还请各位斧正不正确之处。

参考:
1. http://www.jibbering.com/faq/faq_notes/closures.html
2. JavaScript语言精粹

没有评论:

发表评论