使用 JavaScript 进行元编程(网站打不了)

Felix Woo

世界因我存在

2007-8

8

使用 JavaScript 进行元编程

发表于: 16:50 | 分类: 开发技术 | 评论: 2 | 人气: 279 |

转自:http://benchwang.spaces.live.com/blog/cns!1621B5CAD6EB680B!149.entry

Adam McCrea 写了篇使用 JavaScript 进行元编程的文章: Metaprogamming JavaScript。
该文用一个例子来说明元编程。例子很简单,一个 Form 包中两个下拉列表 country 和 state,业务需求是 country 下拉列表中选中“United States”则要显示 state 列表,否则隐藏该下拉列表。处理该逻辑的代码如下:

Event.observe(window, “load”, function() {
Event.observe($(”country”), “change”, function() {
if ($F(”country”) == “United States”)
$(”state-field”).show();
else
$(”state-field”).hide();
});
});

这里用到的对象和方法是 Prototype 对 JavaScript 的扩展。Prototype 是旨在简化动态 Web 程序开发的 JavaScript Framework. 详见 http://www.prototypejs.org/。在上面代码中:Event.observe 在IE下相当于 attachEvent,用于注册事件处理函数。这是注册了 window.onload 和 country.onchange 事件处理程序。$() 是 document.getElementById() 的别名。$F() 会取出 form 中元素当前值。show() 和 hide() 是在 html 元素上增加的方法。通过 prototype 在 html 元素基础上扩展了很多方法。如果想运行上面代码,需要下载 prototype.js 并放置在 html 页面相同目录。完整代码如下:

<html>
<head>
<title>Metaprogramming JavaScript - Example 1</title>
<script src=”prototype.js”></script>
<script type=”text/javascript” charset=”utf-8″>
Event.observe(window, “load”, function() {
Event.observe($(”country”), “change”, function() {
if ($F(”country”) == “United States”)
$(”state-field”).show();
else
$(”state-field”).hide();
});

});
</script>
</head>

<body>
<form>
<p id=”country-field”>
<label for=”country”>Country</label>
<select id=”country”>
<option>United States</option>
<option>Canada</option>
<option>Somewhere Else</option>
</select>
</p>

<p id=”state-field”>
<label for=”state”>State</label>
<select id=”state”>
<option>Ohio</option>
<option>Michigan</option>
<option>Kentucky</option>
</select>
</p>
</form>
</body>
</html>

这些代码满足这样简单的需要没有什么问题。然而随着需求变化,代码会变得繁琐。假如增加如下需求:
增加 province 字段
当 country 为 “Canada” ,显示 province
当 country 为 “United States”,显示 state
当 state 是 “Ohio” 或 “Michigen”,显示 Brutus(很可爱的logo)
根据以上需求,代码修改为:

Event.observe(window, “load”, function() {
Event.observe($(”country”), “change”, function() {
var country = $F(”country”);
if (country == “United States”) {
$(”us-state-field”).show();
$(”province-field”).hide();
} else if (country == “Canada”) {
$(”province-field”).show();
$(”us-state-field”).hide();
} else {
$(”us-state-field”).hide();
$(”province-field”).hide();
}
});

Event.observe($(”us-state”), “change”, function() {
var state = $F(”us-state”);
if (state == “Ohio” || state == “Michigan”)
$(”brutus”).show();
else
$(”brutus”).hide();
});

});

新程序使用先前的事件处理和字段检查方式,尝试扩展程序以满足新的需求。然而这样有几个问题,第一个问题这个代码有两个 bug:1)页面初始载入时所有字段都显示出来了,2)隐藏 state 字段不会,不会自动隐藏 Brutus。后者可称为多米诺(domino)bug,因为如果有其他元素依赖于动态显示和隐藏的字段会导致级联影响。

第二个问题是代码的可读性。不容易立即看出这段代码想达到的目的,因而需要很仔细的检查是否遗漏或者不严格符合需求。当需求发生变化,很希望准确地知道代码什么地方需要修改,当作了修改后,需要有信心确信不会影响其它功能。元编程概念就是用于解决这个问题。

Pragmatic Programmer(实用主义程序员?) 把元编程描述为江代码中的细节抽出来放到元数据中。元数据通常为配置文件或者其他的数据源,当然元数据也可以是可执行代码,只要把“what”(是什么)和“how”(如何做)清晰分离开。该方法的思路是使用易于描述问题论域的词汇来编写代码。问题论域即要描述的“what”。这种类型语言称为领域专用语言(domain specific language),缩写为 DSL。在上面例子中,“what”是显示和隐藏 form 中字段的规则。目前的实现是把规则和规则的实现耦合在一起。随着需求变化和特性增加,代码会变得越来越不清晰。如果能够将这些规则抽出来,规则修改不再依赖于实现,会减少应对需求变化的苦恼。如果使用一种比 JavaScript 更接近问题论域的语言来描述规则,会将问题大幅简化。

编写 DSL 可以从考虑描述业务领域使用的词汇入手。这些词汇有时会因为描述人角色不同而不同。例如程序员、用户、业务分析员就会各不相同。在作出上述假设前,可以考虑一个问题:为什么这些不同角色要使用不同词汇呢?不同词汇在沟通中导致信息失真。通过找到在各组人之间通用的词汇,可以消除信息传递,也就可避免信息失真。这种公共的词汇通常可以在需求说明书中找到:

show us-state when country is “United States”
show province when country is “Canada”
show Brutus when state is “Ohio” or “Michian”
DSL 应该尽可能与上述描述一致。

有可能直接使用上述描述。上述描述并不是可执行的 JavaScript 代码,但可以放在文本文件中,使用 JavaScript 读出来进行解析。这种方法虽然可行,但可能过于复杂。如果使用纯文本作为 DSL,它需要和英语同样的灵活性。但我们希望把它作为数据,它需要遵循一些严格的规则。如果 DSL 本身就是可执行代码,可以将问题简化。不足的一面是非程序开发人员可能不会使用这种 DSL。实际上让非开发人员写DSL也是不现实的目标。如果程序元写好了,业务人员能够看懂或者能够修改,就很不错了。怎样处理例子中的需求,把它转成可执行代码?这可能是最难的一步了,具有很强的主管性。在 JavaScript 中,有两个建议:把方法串起来组成类似于句子的结构,灵活的使用方法名。沿着这个思路,可将上面的业务规则描述如下:

show(”us-state-field”).when(”country”).is(”United States”);

/>show(”province-field”).when(”country”).is(”Canada”);
show(”brutus”).when(”us-state”).is(”Ohio,Michigan”);

方法名“when”和“is”本身表意不完整,但在 DSL 上下文中,这些方法串起来,能够表意很好。可以看出 show() 返回一个对象,该对象具有方法 when();when() 返回一个对象,该对象具有方法 is()。下面给出能够描述第一条规则的简单实现:

function show(fieldToDisplay){
return {
when : function(field){
return {
is: function(value){
if($F(field) == value){
$(fieldToDisplay).show();
}
else{
$(fieldToDisplay).hide();
}
}
}
}
};
};

完整代码如下:

<html>
<head>
<title>Metaprogramming JavaScript - Example 1</title>
<script src=”prototype.js”></script>
<script type=”text/javascript” charset=”utf-8″>
function show(fieldToDisplay){
return {
when : function(field){
return {
is: function(value){
if($F(field) == value){
$(fieldToDisplay).show();
}
else{
$(fieldToDisplay).hide();
}
}
}
}
};
};

Event.observe(window, “load”, function() {

Event.observe($(”country”), “change”, function() {
show(”us-state-field”).when(”country”).is(”United States”);
});

});

</script>
</head>

<body>
<form>
<p id=”country-field”>
<label for=”country”>Country</label>
<select id=”country”>
<option>United States</option>
<option>Canada</option>
<option>Somewhere Else</option>
</select>
</p>

<p id=”us-state-field”>
<label for=”state”>State</label>
<select id=”us-state”>
<option>Ohio</option>
<option>Michigan</option>
<option>Kentucky</option>
</select>
</p>
</form>
</body>
</html>

以上只是一个简单示意,在后续文章中会给出完整的实现。

JavaScript 元编程

 打印

上一篇 Maxthon2正式版发布

下一篇 JavaScript中的作用域

你可能感兴趣的文章

2 条评论  

  1. java综合网 说:

    2007-08-08于16:50

    http://www.javazh.cn/
    不错,不错

    回复

  2. 飞鱼 说:

    2007-08-08于16:50

    这个不错.. 学习了.

    回复

留下评论

名称

电子邮件 (不会被公开)

网站

京ICP备05053527号
经过35次查询历时2.811秒终于生成了此页面
Powered by WordPress & Designed by Felix © 2008

时间: 2024-08-02 06:06:26

使用 JavaScript 进行元编程(网站打不了)的相关文章

10个面向程序员的在线编程网站

在过去的几年里,在互联网上出现了许多为开发人员提供的在线编程网站(Coding playgrounds).这不是一件坏事情,毕竟,如果一个编程网站的话,开发者们迟早会腻的.在这些网站上,你在网页上编写代码,可以实时地看到效果.你可以编辑所有的东西并预览其效果.当然,这些网站最适合编写HTML,CSS和JavaScript代码了.最赞的地方在于他们大多都是免费的,你可以很容易地与别人分享你的编程现场,这很适合于团队工作和创新想法的交流. 如果你深入地想想这种编程模式的话,你就会发现这种模式对于项目

娱教于乐!四大游戏类编程网站,学Python再也不枯燥无味了

前言 学习编程虽然对有些人来说是件乐事,但是对大多数人来说仍然是一件比较枯燥困难的事情.当然,面临这样困惑的人,并不是只有你一个,所以,这世界上就出现了许多寓教于乐的通过游戏的形式来教你编程的网站.让你快乐学习编程. CodinGame 四大游戏编程网站,边玩游戏,边学Python,拒绝枯燥快乐编程 这是一个需要编程一个 AI 机器人,然后由它来解决各种面临的问题的有趣游戏.支持各种编程语言. 支持各种编程语言. 网站: https://www.codingame.com/ Code Comba

ES6入门九:Symbol元编程

JS第七种数据类型:Symbol Symbol的应用场景 11个Symbol静态属性 Symbol元编程 一.JS第七种数据类型:Symbol 在ES6之前的JavaScript的基本数据类型有undefined.null.boolean.number.string.object,现在Symbol作为第七种基本数据类型.翻译symbol这个单词就是“符号,标志”的意思,顾名思义Symbol的应用场景也就离不开唯一性,想想“符号.标志”都是用来干嘛的?不就是用来标记特定事物的符号嘛,在程序中用来作

JavaScript 表单编程

目标:主要是访问用户输入的表单数据,校验用户输入的正确性. 获取表单的引用: //方法一:将表单的ID作为方法的参数 var f1 = document.getElementById("f1"); //方法二:表单集合,得到第一个表单 var f2 = document.forms[0]; //方法三:得到名为fm的表单 var f3 = document.forms["fm"]; //方法四:简写 var f4 = document.fm 访问表单的元素: //获

C++模板元编程 - 2 模仿haskell的列表以及相关操作

这是昨天和今天写的东西,利用C++的可变模板参数包以及包展开,模式匹配的一些东西做的,感觉用typename...比轮子叔那个List<A,List<B, List<C, D>>>的设计要好看不少. List有一个很巧妙的继承,只有那么做才能使用类似于List<>::Rest的写法,直接定义成template<typename T, typename... TArgs>List是不行的. Change这里可以给一个args...换另一个包装,这里

《Effective C++》:条款48:认识template元编程

Template metaprogramming(TMP,模板元编程)是编写template-based C++程序,编译的过程.template metaprogramming是用C++写的模板程序,编译器编译出具体化的过程.也就是说,TMP程序执行后,从templates具体化出来C++源码,不再是模板了. TMP有两个作用,一是它让某些事更容易.例如编写STL容器,使用模板,可是存放任何类型元素.二是将执行在运行期的某些工作转移到了编译期.还有一个结果是使用TMP的C++程序可能在其他方面

C++拾遗--模板元编程

C++拾遗--模板元编程 前言 模板元是用于递归加速的,把运行期的函数调用变到编译期进行代码展开,类似于内联函数.下面看一个实例:斐波那契数列第n项求解. 模板元编程 #include <iostream> #include <ctime> using namespace std; //递归法 int fib(int n) { if (n < 0) return 0; if (n == 1 || n == 2) return 1; return fib(n - 1) + fi

模板元编程

//模板元把运行时消耗的时间,在编译期间优化 //递归极其消耗时间 1 #include <iostream> 2 3 //模板元把运行时消耗的时间,在编译期间优化 4 //递归极其消耗时间 5 6 template <int N> 7 struct data 8 { 9 enum { res = data<N - 1>::res + data<N - 2>::res }; 10 }; 11 12 template <> 13 struct da

初识C++模板元编程(Template Mega Programming)

前言:毕设时在开源库上做的程序,但是源码看得很晕(当时导师告诉我这是模板元编程,可以不用太在乎),最近自己造轮子时想学习STL的源码,但也是一样的感觉,大致了解他这么做要干什么,但是不知道里面的机制.于是开始学习<C++模板元编程>,看完第二章对一些东西豁然开朗. PS:该书也有点老了,C++11标准还没出来,主要用的Boost库. Traits(特征) 说正题,在STL中经常可以见到后缀为traits的名字,比如经常用到的std::string,本质是类模板basic_string的第一个参