原型(Prototype):减少AJAX的开发痛苦

                                            原型(Prototype):减少AJAX的开发痛苦
                                                                                      作者: Bruce Perry
                                                                                          April 05, 2006
 
本文所描述的原型(Prototype),是一个开源的JavaScript库,用来为AJAX应用创建一个对象。我通过描述一个面向Web应用的环境系统来解释如何使用原型(Prototype),这个系统用来显示年度的二氧化碳浓度水平。首先,我将讨论原型(Prototype)的好处,并且描述怎么在你的应用里安装原型(Prototype);其次,我还将深入地探讨这个系统怎么使得原型(Prototype)库有着很好的应用实践。
 
什么是原型(Prototype
为什么我不为我的应用直接创建一个简单的、成熟的JavaScript对象(POJO),而是引进一个开源库?第一,原型(Prototype)收集了很多漂亮的有关于JavaScript的捷径用法,它减少输入,并且避免重复发明轮子。最常用的、值得夸奖的捷径方法是 $("mydiv"),这是一个原型(Prototype)函数,返回一个与id为“mydiv”的HTML标签相关的文档对象模型(DOM)元素。这种类型的简化完全值得我们在安装原型(Prototype)上的花销。而不安装它、与 $("mydiv")相等的表达式为:
document.getElementById("mydiv");
另外一个有用的原型(Prototype)的捷径方法是 $F("mySelect"),用来返回一个Web页面上的HTML表单的元素的值,例如一个选择列表。一旦你习惯了原型(Prototype)的严谨的、透明的语法,你就会随时使用这些捷径方法。原型(Prototype)也包含了很多的定制对象、方法和很多用来编译JavaScript对象的扩展。例如 EnumerationHash对象(我在下面将要讨论到)
最后,原型(Prototype)也通过它自己的 Ajax.Request和相关的对象包装了 XMLHttpRequest的功能。所以你不用费心去编写代码为各种各样的浏览器去启动对象。
 
安装
怎样安装原型(Prototype)呢?首先,在 prototype.conio.net网站上下载它,原型(Prototype)是一个开源的项目,能够在 an MIT-style license授权下使用。下载的文件包括 prototype.js文件,这是一个JavaScript文件,它定义了各样各样的在你的应用中要使用到的方法、对象。在你的应用中添加 prototype.js文件的方法是在HTML文件中使用一个 script标签。
<head>...
<script src="js/prototype.js" type="text/javascript">
</script>
<script src="js/co2.js" type="text/javascript">
</script>
<script src="js/eevpapp.js" type="text/javascript">
</script>...
</head>
 
在你的应用程序中的包含HTML文件的同一极目录里,也包含了一个叫 js的目录。这个 js目录包含了 prototype.js,在 co2.js文件中定义了一个对象,这将在本文中加以描述,就跟客户端的其他代码在另外一个文件: eevapp.js中一样。
既然应用已经引入了原型(Prototype)文件,那么其他的引入了 .js文件的JavaScript代码就能够使用原型对象及其扩展,如果它们在本地被声明和定义了的话。JavaScript不需要像例如 importrequire这样的语句来使用其他JavaScript文件的对象,这些JavaScript文件只需要浏览器一般引入就行了。
 
气候变化
原型(Prototype)是怎么来帮助我们实现应用的需求的呢?需求又是什么呢?
用户接口是一个Web浏览器,例如Safari 1.3、Firefox 1.5、Opera 8.5或者 Internet Explorer 6。应用被设计来显示小数据量的年度的大气层二氧化碳水平。这是数值性的数据,像377,代表的是某一个年度在大气中的百万分之几的二氧化碳的水平。我决定在一个JavaScript对象中存储这些年份和数值,这些对象能够从应用中下载到浏览器上。没有必要使用数据库来存储这些数据,因为它们规模太小,不需要安全或者认证。这些数据被设计来供感兴趣的公众使用。然而,应用的确有了如果必要的话,在飞行中对JavaScript对象添加新的数据的能力。
 
CO2:Applet
图1-1显示了应用的浏览器界面。左上角是一个Applet,用来显示大气中二氧化碳的水平,当用户选择一个年份的时候。
数据是从运行在Hawaii的政府网站 Mauna Loa Observatory上获得。它的测量是在高海拔上的一般测量。全世界的科学家都在它们的气候变迁研究中使用这些数据。
有46个年度等级,从1959-2004(2005年的数据现在还没有获得)。因而,这使得我们使用JavaScript对象来保存信息。甚至当我们需要使用这个工具选择显示这些年的月度水平(有超过500的分离数据),我们也是在客户端保存数据,没有数据库或额外的服务器。
 
原型(Prototype )在哪里被使用
eevapp.js文件包含了当用户在选择框选择一个年度的时候需要执行的代码:
//instantiate an object 
//defined in the co2.js file 
var co2lev = new CO2Levels();
//the onload event handler executes
//when the browser is finished loading the page.
window.onload=function(){
$("co2_select").onchange=function(){
    $("co2ppm").innerHTML= 
    co2lev.getYear($F("co2_select")); 
    }
 
};
 
"co2_select"是用户选择一个年份时选择框的id值。
<select id="co2_select" .../>
 
代码:
$("co2_select")
 
返回一个DOM元素的引用。和表达式 document.getElementById("co2_select");相同。
代码给选择框的 onchange事件处理属性赋予了一个JavaScript方法,如:
$("co2_select").onchange=function(){...}.
用一个简单的解释,当用户在 select标签里选择一个年份的时候,浏览器执行指定的方法。这个方法要做什么呢?这个方法取得一个HTML div元素的 id "co2ppm",再一次使用原型(Prototype)的快捷方法,这个 div元素的 innerHTML属性,代表的是用户在浏览器中看到的内容,被赋值为一个方法调用的返回值:
co2lev.getYear($F("co2_select"));
 
eevapp.js文件的最开始, co2lev对象被初始化。
var co2lev = new CO2Levels();
 
这个对象有一个 getYear()方法。这个方法取得一个字符串,代表年度的参数,如 "1999",返回一个相关年份的二氧化碳的水平。
 
精炼的语法
那个美元符号在表达式 $F("co2_select")中又出现了一次,原型(Prototype)方法 $F()返回的是HTML表单元素的值,在这个例子中,是选择框,我把它的 id作为一个参数传递到方法中。当用户选择一个不同的年份的时候,应用使用这个方法来改变显示CO2的水平。
一个小提示:记住,如果选择框的子 option没有 value属性, $F()不能从一个选择框中返回值。就像: <option value="1959">1959</option>。换句话说,至少在我使用的原型(Prototype)版本1.4.0中,如果我省掉了 value="..."$F()不会有返回值。
 
对象视图
CO2Levels对象的定义出现在一个不同的JavaScript文件中,即 co2.js。图1-2显示了一个描述该对象的UML类图。
图1-2 UML类图
 
下面是 CO2Levels对象的整个代码。第一行初始化一个新的对象,使用从原型(Prototype)继承来的语法。局部变量 levels是一个对象,像一个联合数组,和年度以及对应的CO2水平相关联。我因为可读性省略了大多数的年份。
var CO2Levels=Class.create();
CO2Levels.prototype = {
/*
Source: http://cdiac.esd.ornl.gov/ftp/trends/co2/maunaloa.co2
Mauna Loa Observatory, Hawaii
*/
initialize: function(){
    this.levels={ "1959":315.98,"1960":316.91,
    "1961":317.65,"1962":318.45,
    "2003":375.64,"2004":377.38};
    this.levelsHash=$H(this.levels);
},
    
getYear: function(year){
    if (! isNaN(year)) {
        return this.levelsHash[year];
    }   else {
        return 377;
    }
},
    
keys: function(){
    return this.levelsHash.keys();
},
    
values: function(){
    return this.levelsHash.values();
},
 
inspect: function(){
    alert( this.levelsHash.inspect());
},
 
add: function(year,level){
    var tmp = new Object();
    tmp[year] = level;
    this.levelsHash=this.levelsHash.merge(tmp);
}
 
}
 
创建原型(Prototype )对象
在Prototype中使用 Class.create()方法返回一个JavaScript对象,这个对象通过 initialize()方法提供这个对象的一个新的实例。这和构造器方法的功能相同,例如Java中的。当每次代码产生一个新的 CO2Levels对象, initialize()方法都要被调用。代码的余下部分为这个 CO2Levels对像定义原型(Prototype),或者蓝图。包括它的 initialize()方法的各种行为。 initialize()方法要做什么呢?它创建了一个叫 levels的局部变量,这个局部变量引用了一个保存所有数据的对象,这些数据包括CO2水平以及相应的年度。代码接着把这些对象转化到 Hash对象中,为对象提供更多的功能(例如察看对象内容和新增新的数据的功能)。
this.levelsHash=$H(this.levels);
 
原型Hash 对象
这里又有一个语法 $H(),这个方法获取一个JavaScript对象作为参数,返回原型(Prototype)的 Hash对象。和其他语言的hash table结构相似。 Hash有一个关联的数组结构,和一些方法来操作这些数据。例如增加新的数据到 Hash
例如, Hash.keys()方法返回由所有的 Hash的 key组成的一个数组(例如在我们的数据中的所有的年度)。 values()方法返回的是所有值(CO2水平)的数组。 merge()方法增加新的键值对到 Hash中。
 
委派
我们的 CO2Levels对象使用了委派的概念,在其中调用自己的 keys(), values(), 和 add()方法来委派这些实际的操作到一个内部的 Hash对象。这个对象被作为一个局部变量: levelsHash保存。
让我们看看 getYear()方法:
getYear: function(year){
    if (! isNaN(year)) {
        return this.levelsHash[year];
    }   else {
        return 377;
    }
}
 
这个内置的 isNaN()方法返回假,如果它的参数能够作为一个数值(如“2000”)计算的话,相反则是真(如 isNaN("hello"))。如果 getYear()参数通过了这个测试,那么代码使用一个普通的JavaScript表达式来返回一个键或属性的值: this.levelsHash[year]this.levelsHash["2004"]计算结果为377.38)。浏览器于是在HTML div元素内部显示这个数值。
 
添加新的内容到现有的Hash
CO2Levels对象有一个 add()方法,能够增加新的键值对(额外的年度和CO2水平)到一个现有的数据中。
add: function(year,level){
    var tmp = new Object();
    tmp[year] = level;
    this.levelsHash=this.levelsHash.merge(tmp);
}
 
这个方法根据它的两个参数(代表年度和CO2水平)创建了一个新的对象,这看起来像 {"2005":381}
代码再将这个对象传递到原型 Hash对象的 merge()方法。这个方法组合了一个新的对象到 Hash的已有数据中,实质上是将它们合并到一个数据集团或关联数组。
merge()方法返回已有的数据,但是一个新的属性/值对增加到了末尾。
通过一些重构,代码能够使用 XMLHttpRequest从Mauna Loa Observatory上抓取新的数据,然后添加到已有的客户端数据中。
 
检测
最后,原型 Hash对象也有一个 inspect()方法。这个方法产生一个可读的 Hash内容的显示。如图1-3:
图1-3 看看 Hash的内部
CO2Levels对象委派它自己的 inspect()方法任务到一个内部的原型 Hash对象。
inspect: function(){
    alert( this.levelsHash.inspect());
}
 
这是一个非常有用的debug工具,用来察看 Hash对象的当前内容。
 
后续的文章将要讨论在同样的应用中AJAX的缓存策略。它将介绍原型的 Ajax.Request对象。它用来减少代码数量,并且专心使用 XMLHttpRequest对象。这是一个重要的高级的JavaScript对象,在AJAX应用中,它在幕后产生HTTP连接。
 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值