负暄琐话

我的email: rot47('649@ 6(hF+`hd"w=92vhG{>}G3"@l M >:>6?4@56 \F')

囧囧ID:g9yuayon
858932次访问,排名32好友20人,关注者24
姓名:g9yuayon
前世:夜郎国厚脸皮神棍
魅力指数:0
名气:1
宠物:一只从来不对生人叫的看门狗
g9yuayon的文章
原创 244 篇
翻译 4 篇
转载 48 篇
评论 849 篇
g9的公告
最近评论
icoding:恩。这年头牛人也不好混啊
icoding:离开IBM也不和咱说一下
LINSOSO:“每头成员”里面的这个“头”字用得是那么地经典。。。
xingranliuyun:老大总是能用简单的话语点起大家无限的激情。

看了这篇文章我有一种燃的感觉。

愿爱伴老大一路前行!
xingranliuyun:老大加油,相信凭你的实力没啥问题。
文章分类
收藏
    相册
    旅游
    计算机科学
    Lambda the Ultimate
    软件开发
    Reddit编程专栏(RSS)
    正在读的书
    存档
    订阅我的博客
    XML聚合  FeedSky

    原创 诡异的JavaScript Closure收藏

    新一篇: 为什么程序员总加班? | 旧一篇: Kaye效应的录像

    出来混,迟早要还。今天写JavaScript代码,才知道一个循环里的函数共享同一闭包 三个闭包共享一个变量。比如下面的代码是错的,不能正确报告每个事件对应的描述:

    var div = document.getElementById("testDiv");
    var events = {onclick: "clicked", onchange: "changed",  onmouseover: "mouse over"}; 

    for(var e in events){
       div[e] 
    = function(){
          alert(events[e]);
       };
    }

    试一下就知道。不管激发events列表里的哪坨事件,alert弹出的窗口里总是"mouse over"。

    不明白JavaScript为什么这样处理循环和闭包的关系。哪位老大指点一下? 更新:随便猜一下。JavaScript的Closure环境由静态的句法结构确定。也就是说,代码一旦写成,我们就知道函数的自由变量同哪些环境里的变量绑定。这样说来,上面的循环只申明了一个变量p和一个内部函数,从静态的句法结构来看,我们的确只有一个环境。因此,虽然运行时同一个内函数被调用多次,创建了多个闭包,这些闭包指向的都是同一个环境里的同一个变量。这样同JavaScript规定的闭包语义一致。

    阳春版的修改办法是利用函数定义创建新闭包,符合业内名言:任何计算机问题都能通过多加一层抽象解决。:-) Crockford Douglas 把多加的这层函数叫做因子函数(factor function)。

    var div = document.getElementById("testDiv");
    var events = {onclick: "clicked", onchange: "changed",  onmouseover: "mouse over"}; 

    for(var e in events){
       div[e] 
    = function(e){
           
    return function(){
               alert(events[e]);
           };
       }(e);
    }

    当然,如果到处创建因子函数,就繁琐了。所以还是Dojo风格的调用来得清爽:

    dojo.lang.forEach(events, function(e){
        alert(e);
    });

    明眼老大们自然可以看出这是函数编程的风格。其实JavaScript本就是采用C语言句法的简化版LISP,异常灵活。如果我们注意利用高端函数(加上闭包),便可像搭建积木那样“拼装”我们的程序,使代码变得干净利落。Dojo框架里实现了各式函数编程常用函数,比如map, reduce, filter, find, hitch, curry, 非常方便。再加上prototype chain, 对inspection的强大支持(光arguments.callee就让俺爱不释手了),以及call, apply, eval这三个超级函数,在JavaScript里写出功能完善的DSL也变得相对容易。 就算不捣腾DSL,JavaScript也有无数妙用。比如Dojo里处理事件的代码实现了AOP风格的建议功能,让我们随意操纵处理事件的时机,轻松截取任意事件的参数,哪怕是普通JavaScript函数调用的参数。而实现这些功能的代码并不复杂。

    从Dojo的实现也可以看出学习多种编程范式的重要性。Dojo里支持函数编程,面向对象编程,Ruby风格的mixin, AOP风格的事件处理等从不同语言借鉴来的功能。如果Dojo的主程Alex Russell只懂JavaScript,就算他能倒背EMCAScript规范,恐怕也写不出Dojo。要享受编程,避免一件本来很美好的事变成体力活,功夫永远在诗外。

    发表于 @ 2007年04月18日 13:43:00|评论(loading...)|编辑

    评论

    #remaker 发表于2007-04-19 10:48:32  IP: 123.112.2.*
    这个不是“一个循环里的函数共享同一闭包”,而是“三个闭包共享同一个自由变量e”。在第一段代码的for语句后面(循环体外)加一句“e = "onchange";”弹出的窗口里就总是“changed”了。

    其实,当“一小段可以执行的东西”讲的时候,“Clause”(标题里的拼写好象不太对?)还是翻译成“子句”或者“从句”比较达意。
    #g9yuayon 发表于2007-04-19 14:07:13  IP: 74.123.144.*
    remaker: 谢谢指正。按照流行的闭包定义(运行时函数和它环境的绑定),说三个闭包共享同一环境所以也绑定到同一自由变量应该更确切。我也是看有人用“函数执行与同一闭包绑定”的说法,就人云亦云了。:-) 。拼写是对的。闭包应该是Closure的通用翻译,和从句无关。
    #harryzou 发表于2007-04-19 15:32:20  IP: 221.238.245.*
    从《Pro JS》上看到的,个人感觉这么写舒服一点儿:)
    for(e in events){
    (function(){
    var t=e;//每个闭包使用不同的变量
    div[t] = function(){
    alert(events[t]);
    };
    })();
    }
    #lishu1980 发表于2007-04-19 18:51:07  IP: 218.5.3.*
    要把这些编程思想组合起来,用好他们,不是件容易的事
    #remaker 发表于2007-04-19 19:45:27  IP: 221.221.248.*
    嘿嘿,互相指正一处,就算扯平了吧(不过好象我错得更低级些,于是还有得赚)。
    #hhwytfliq 发表于2008-05-19 05:19:17  IP: 121.15.9.*
    楼上滴说话有鲁迅风格-_-
    发表评论  


    当前用户设置只有注册用户才能发表评论。如果你没有登录,请点击登录
    Csdn Blog version 3.1a
    Copyright © g9