jQuery与MooTools库的一些比对(1)
我上大学那会儿从事的项目用的是jQuery,毕业后工作所从事的项目用的是MooTools。很幸运短期内有机会接触两款不同设计风格的优秀的JavaScript库。今天就我自己的一些认识比对下这两个JS框架,更多的是希望大家能够对MooTools这个JS框架有更多的认识。毕竟,大多数从事web前端的人对上手容易的jQuery更熟悉些。
51CTO推荐专题:jQuery从入门到精通
一、API设计
就API的设计上来讲,无论是MooTools,或是其他类似YUI的JS框架都比jQuery略逊一筹。
API是什么?根据某些著作的回答,API是对所需知识的抽象,它将系统的复杂性隐藏起来。例如汽车的方向盘,电视机上的按钮。一个API设计的好坏可以从下面几个方面评估:可理解性、一致性、预见性、简单性、保护性。
◆ 可理解性
例如selector(选择器)。随便举个选择器的例子(jQuery):
- $("#jQuery div")
选择器的写法是与CSS的选择器是一脉相承的。因此对于很多写页面的人来讲,可以很轻松地使用jQuery找到自己想要的那根葱。jQuery后来的版本之所以把XPath干掉,或许就是因为理解性上的问题吧。当然,MooTools也是支持CSS选择器的,只不过,其不是使用一个美元符号$,而是两个$$,貌似是学习prototype框架,返回的是数组。
- $$("#MooTools div")
如果MooTools只走到这一步,我觉得还好,貌似跟jQuery的可理解性打个小平手。只可惜,MooTools还有一个单个美元符号$的选择器,其中参数只能是元素的id,例如:
- $("MooTools")
这玩意,选择的貌似是有个MooTools元素扩展方法的对象。如果不存在,应用元素方法的时候(eg: addClass)则会报错。
也就是说MooTools选择元素,根据用法的不同,有时候返回的可能就是数组,有时候又是元素对象。这难免让对JS熟悉,对CSS较熟悉的人员有了理解和使用上的困难了。不过这不能怪MooTools,设计架构上的不同导致MooTools有时候需要返回元素对象,而不是元素对象数组。
因此,从理解性上来说,MooTools逊于jQuery了。
◆ 一致性
JS框架的一致性的主要体现之一就是链式调用,例如(jQuery):
- $("#jQuery").css("color", "red").height(200);
MooTools也是支持链式调用的,例如(MooTools):
- $$("#MooTools").setStyle("color", "red").setStyle("height", 200);
在链式调用上,jQuery和MooTools基本上都是很OK的。
但是,在其他方面的一致性上,MooTools似乎又落于下风了。jQuery这个框架真的很神奇,一个$符号就可以从广州走到北京,真可谓万能密匙啊。
首先选择器,例如$("#jQuery")肯定是$符号,然后,其相关的其他些方法,例如插件机制之$.fn.extend(object),或者是Ajax请求$.ajax([options]),又或是浏览器检测,数组对象方法等等等等都是$符号横行的。
但是,MooTools桑中$符号出现在选择器,让人难懂的$A, $E,以及一些公共方法命名上,其余时候都回家睡觉觉了。
继承需要new Class()构造,Ajax请求为new Request([options]),然后浏览器检测又是以Browser开头。数组,字符串等方法又都是当前对象本身打头,如myString.trim()。毫无一致性可言,显然,这个的学习成本和使用难度要比jQuery大多了。
◆ 预见性
好的API应该考虑到用户的无绪性选择(selective cluelessness)以及预见未来可能发生的一些事情。
不知是John Resig(jQuery 之父)确实想的很远,还是因为幸运,或是只因为John是个天才,jQuery的设计让其似乎不会与未来发生冲突。
举个老到啃不动的例子,过滤字符串的前后空格。jQuery的做法是:
- $.trim(myString);
MooTools做法是:
- myString.trim();
乍一看,似乎MooTools框架的做法更符合我们的理解 → 字符串对象有个trim方法,返回过滤前后空格的字符串方法。However,随着时间拖移,有些事情就开始发生变数了。
在ECMAScript 5(ES5)中,字符串是内置trim方法的。我们可以做个小小的测试,如下代码:
- alert((" foo ").trim());
您可以狠狠地点击这里:ES5 内置trim方法测试
例如,在我的FireFox 6浏览器下,弹出的就是foo,如下截图:

对于一些有历史价值的浏览器,就不支持,例如IE7模式下:

同样类似的就是基于Function扩展的bind方法,MooTools中有,但是,ES5中也内置了。只是,比较幸运的是,无论是字符串trim方法,或是函数bind方法,虽然名称冲突了,但是,所实现的功能确是一样的,因此,也算不上冲突了。但是,万一哪天遇到个不幸,MooTools中的某个方法与ES5中的方法同名但不同功能,然后,只能老泪纵横了!
再举个预见性的例子,选择器选择对象以及DOM对象。jQuery对jQuery对象和原生dom对象进行了分离,例如:
- $("input").bind("focus", function() {
- alert(this.value); // dom对象
- alert($(this).val()); // jQuery包装器对象
- });
但是,在MooTools中,一些方法是在原生DOM上扩展的,MooTools元素对象和原生dom是合体的,例如:
- $$("input").addEvent("focus", function() {
- alert(this.value); // dom对象
- alert(this.get("value")); // 扩展后的dom对象
- });
“合体”的问题在于随着浏览器以及一些规范的发展,原生dom可能会支持其他的一些方法,这些方法有可能就和MooTools插件中DOM扩展方法冲突。好在MooTools的方法命名属于对称命名,且语义明显,这种设计可以有效避免与原生dom方法的冲突。但是,事情没有这简单……下面你可以看到MooTools中DOM元素方法的设计的一些问题(当然,不可否认,这种设计使用上相对灵活些)。
◆ 简单性
jQuery之所以让开发者恋恋不舍,原因之一就是其简单。jQuery的口号就是"write less, do more."
拿dom-style的API举例,MooTools, YUI等框架采用的是传统对称命名的方式(prop为property属性缩写):
- el.setStyle(prop, val);
- el.getStyle(prop);
- el.setStyles({ propA: valA, propB: valB });
- el.getStyles(propA, propB); // MooTools支持, 返回是个名-值对象
在jQuery里,一个CSS就把所有瓷器活都揽了:
- el.css(prop); // 表示 getStyle
- el.css(prop, val); // 表示 setStyle
- el.css({ propA: valA, propB: valB }); // 表示 setStyles
- el.css(prop, func); // func 是一个返回 val 值的函数
虽然参数类似,但是jQuery只要记一个名字,而MooTools却要N个,且名字也比较长(必须完整且长,否则易出问题)。这也是为什么jQuery更容易上手的原因。而且,jQuery更近一步,还支持func回调,且参数可以map, val可以是函数,暗藏多多surprise啊。
显然,简单性这块又是jQuery好一些。
这里,我还想说点其他相关的东西。jQuery框架的短命名设计确实好,于是我就想对MooTools的元素方法进行扩展,使等同于jQuery的命名书写方式,一是省些代码,二是方便熟悉jQuery的新员工上手,拿还是上面dom-style的例子,MooTools如下扩展处理:
- Element.implement({
- //将mootools默认的setStyle以及setStyles方法转化为与jQuery类似的css()形式
- css: function(key, value) {
- if ($type(key) == 'object') {
- for (var p in key) this.css(p, key[p]);
- return this;
- }
- if(!$chk(value)){
- return this.getStyle(key);
- }
- this.setStyle(key, value);
- return this;
- }
- });
于是,MooTools也支持CSS方法,例如可以直接$("mootools").css({ border: "1px solid #ddd" });。恩,看上去不错,确实,上面的扩展在目前各个浏览器中是没有任何问题的。于是,初尝到了甜头,我们就想模拟其他jQuery包装器方法的扩展,例如width/height方法,如下(width举例):
- Element.implement({
- width: function (val) {
- if ($chk(val)) {
- return this.setStyle("width", val);
- } else {
- return this.getWidth();
- }
- }
- });
看上去不错,不是吗?但是,人生不如意事八九,上面MooTools框架对dom进行的width方法扩展是有问题的。我们都知道,<img>元素是有width属性的。正如上面提到的,MooTools框架的元素方法是在DOM上面直接“合体”扩展的。于是乎,对于图片而言,使用上面扩展的width方法是会嗝屁的——原生属性与扩展方法冲突。
- alert($("image").width()); //报错,显示$("image").width不是function
由此又进一步证实了jQuery在API设计上更能避免一些当下或未来潜在的冲突,更具远见性。
◆ 保护性
jQuery有个多库共存机制,可以有效地保护其他框架都在争夺的$符号,有效避免了一些兼容性的问题。
- jQuery.noConflict();
- (function($) {
- $(function() {
- // 使用 $ 作为 jQuery 别名的代码
- });
- })(jQuery);
- // 其他用 $ 作为别名的库的代码
而MooTools中似乎并无这样的机制。
总结:就API设计这点来讲,jQuery几乎从各个方面都强于MooTools,这也是jQuery大行其道的主要原因。
二、性能
◆ 选择器性能
MooTools框架官方页面提供了选择器性能测试页面:speed/validity selectors test for frameworks
点击右上角的"start tests"按钮,一段时间后就可以看到各个框架下各个选择器测试结果了。下表为我联系测试三次后的结果记录,可以看到,jQuery选择器的总体性能略比prototype低,比MooTools要强。但是,在我们实际些页面做交互的时候,其中选择器的差异基本上可以忽略不记(YUI在:nth-child选择器上的糟糕表现肯定要提防的)。

◆ dom操作性能
本来想从网上找一下MooTools和jQuery框架在dom操作这块的性能对比数据,结果发现,压根就没有,连个沾边的都没有。在这艰难困苦的时候,想起了伟大领袖毛主席的一句话:“自力更生,艰苦创业”。心中的小宇宙顿时爆发了,快刀乱麻,一番折腾后弄出了自己想要的测试页面。
您可以狠狠地点击这里:MooTools与jQuery一些dom操作性能对比
下面就是测试结果哈:
可以看到,除了setProperty/attr和setProperties/attrMulti方法MooTools框架性能是略微占优外,其余一些dom相关操作都完败jQuery。
小小总结:就性能这块。MooTools框架无论是选择器或是其他一些方法性能都逊于jQuery。








