- 在线时间
- 1 小时
- 信用度
- 2122
- 最后登录
- 2015-9-21
- 注册时间
- 2007-3-8
- 精华
- 2
- 阅读权限
- 100
- UID
- 4
|
1楼
发表于 2007-4-18 21:12:48
|
查看: 2406 |
回复: 1
出来混,迟早要还。今天写JavaScript代码,才知道一个循环里的函数共享同一闭包。比如下面的代码是错的,不能正确报告每个事件对应的描述:
[color=#0000ff]var[/color][color=#000000] div [/color][color=#000000]=[/color][color=#000000] document.getElementById([/color][color=#000000]"[/color][color=#000000]testDiv[/color][color=#000000]"[/color][color=#000000]);
[/color][color=#0000ff]var[/color][color=#000000] events [/color][color=#000000]=[/color][color=#000000] {onclick: [/color][color=#000000]"[/color][color=#000000]clicked[/color][color=#000000]"[/color][color=#000000], onchange: [/color][color=#000000]"[/color][color=#000000]changed[/color][color=#000000]"[/color][color=#000000], onmouseover: [/color][color=#000000]"[/color][color=#000000]mouse over[/color][color=#000000]"[/color][color=#000000]};
[/color][color=#0000ff]for[/color][color=#000000](e [/color][color=#0000ff]in[/color][color=#000000] events){
div[e] [/color][color=#000000]=[/color][color=#000000] [/color][color=#0000ff]function[/color][color=#000000](){
alert(events[e]);
};
}[/color]
试一下就知道。不管激发events列表里的哪坨事件,alert弹出的窗口里总是"mouse over"。
不明白JavaScript为什么这样处理循环和闭包的关系。哪位老大指点一下?
阳春版的修改办法是利用函数定义创建新闭包,符合业内名言:任何计算机问题都能通过多加一层抽象解决。:-) Crockford Douglas 把多加的这层函数叫做因子函数(factor function)。
[color=#0000ff]var[/color][color=#000000] div [/color][color=#000000]=[/color][color=#000000] document.getElementById([/color][color=#000000]"[/color][color=#000000]testDiv[/color][color=#000000]"[/color][color=#000000]);
[/color][color=#0000ff]var[/color][color=#000000] events [/color][color=#000000]=[/color][color=#000000] {onclick: [/color][color=#000000]"[/color][color=#000000]clicked[/color][color=#000000]"[/color][color=#000000], onchange: [/color][color=#000000]"[/color][color=#000000]changed[/color][color=#000000]"[/color][color=#000000], onmouseover: [/color][color=#000000]"[/color][color=#000000]mouse over[/color][color=#000000]"[/color][color=#000000]};
[/color][color=#0000ff]for[/color][color=#000000](e [/color][color=#0000ff]in[/color][color=#000000] events){
div[e] [/color][color=#000000]=[/color][color=#000000] [/color][color=#0000ff]function[/color][color=#000000](e){
[/color][color=#0000ff]return[/color][color=#000000] [/color][color=#0000ff]function[/color][color=#000000](){
alert(events[e]);
};
}(e);
}[/color]
当然,如果到处创建因子函数,就繁琐了。所以还是Dojo风格的调用来得清爽:
[color=#000000]dojo.lang.forEach(events, [/color][color=#0000ff]function[/color][color=#000000](e){
alert(e);
});[/color]
明眼老大们自然可以看出这是函数编程的风格。其实JavaScript本就是采用C语言句法的简化版LISP,异常灵活。如果我们注意利用高端函数(加上闭包),便可像搭建积木那样“拼装”我们的程序,使代码变得干净利落。Dojo框架里实现了各式函数编程常用函数,比如map, reduce, filter, find, hitch, curry, 非常方便。再加上prototype chain, 对inspection的强大支持(光arguments.caller, arguments.callee就让俺爱不释手了),以及call, apply, eval这三个超级函数,在JavaScript里写出功能完善的DSL也变得相对容易。 就算不捣腾DSL,JavaScript也有无数妙用。比如Dojo里处理事件的代码实现了AOP风格的建议功能,让我们随意操纵处理事件的时机,轻松截取任意事件的参数,哪怕是普通JavaScript函数调用的参数。而实现这些功能的代码并不复杂。
从Dojo的实现也可以看出学习多种编程范式的重要性。Dojo里支持函数编程,面向对象编程,Ruby风格的mixin, AOP风格的事件处理等从不同语言借鉴来的功能。如果Dojo的主程Alex Russell只懂JavaScript,就算他能倒背EMCAScript规范,恐怕也写不出Dojo。要享受编程,避免一件本来很美好的事变成体力活,功夫永远在诗外。 |
|