mootools是一個簡潔,模塊化,面向?qū)ο蟮膉avascript框架。它能夠幫助你更快,更簡單地編寫可擴展和兼容性強的javascript代碼。mootools跟prototypejs相類似,語法幾乎一樣。但它提供的功能要比prototypejs多,而且更強大。比如增加了動畫特效、拖放操作等等。建議大家可以用它來代替prototypejs。
我為什么選擇mootools,拋棄了prototype. (mootools 與 prototype 核心代碼分析) 
=========================================== 
前言 
=========================================== 
最近喜歡上了mootools(相見恨晚啊),在公開表示了對他的偏愛. 
很多朋友都問我為什么要移情別戀,其實理由還是蠻多的. 
今天在這里打算列舉出一部分.讓更多的朋友能夠了解一下mootools,也希望有更多的朋友喜歡上他. 
文章的標題注定了我會更多的講述 mootools比prototype好的地方, 
希望大家不要被我的誤導,以為mootools處處都比prototype好. 
mootools還是有一些不足的. 
本次對比針對 mootools 1.11版 和 prototype 1.51版, 
只比較了一些核心代碼,其他的工具方法,輔助函數(shù)不再本文討論之內(nèi). 
開始前,再次重申一遍:我曾經(jīng)很愛prototype,而且我將永遠都會用"偉大"來形容它. 
好 下面對比正式開始 ( 
mootools以下簡稱moo. 
本文所引用的代碼, 只是起到說明作用,不保證他們都可以被正確的執(zhí)行. 
同時為了使本文簡潔一些,引入的 一些 moo和prototype的代碼也只是片段或是偽代碼. 
) 
=========================================== 
一. 類機制 
=========================================== 
js里的類實際上就是function. 
如果不使用任何框架和組件,那么想創(chuàng)建一個自己類也不是難事,方法如下: 
java代碼
var personclass=function(name,gender){	this.name=name;	this.gender=gender;	alert("my name is "+this.name);}var mygirlfriend=new personclass('vickey','female');執(zhí)行 后, 會創(chuàng)建一個personclass類的實例mygirlfriend, 并執(zhí)行function內(nèi)的語句. 
那些語句可以理解為是類的構造函數(shù). 
prototype 
現(xiàn)在來看看在prototype的幫助下如何去定義這個類: 
java代碼
var personclass = class.create();personclass.prototype.initialize=function(name,gender){	this.name=name;	this.gender=gender;	alert("my name is "+this.name);};var mygirlfriend=new personclass('vickey','female');//如果想給類增加屬性和方法時使用 personclass.prototype.xxx=...;//或者是使用 prototype提供的 object.extend(personclass.prototype, {...} );
(關于object.extend稍后在對比繼承機制時再細說.) 
再來看看prototype是實現(xiàn)類機制的核心代碼. 
java代碼
var class = {  create: function() {    return function() {      this.initialize.apply(this, arguments);    }  }}
通過看代碼不難看出,prototype的class實際上只是幫助我們抽象出了"類的構造函數(shù)". 
而當我們在prototype的這種機制下進行類的定義時,實際上帶來的好處是非常有限的. 
prototype的class只是從結構對我們的類進行了重新規(guī)劃. 而這樣的規(guī)劃意義并不是很大. 
而且prototype帶有強制性,即, initialize 是必須要定義的. 
實際上這里存在一個缺陷, class應該提供一個默認的initialize(一個空函數(shù)就好), 
或者是在create返回的function里進行必要的判斷. 
(prototype1.6的類機制變化比較大,但是還沒仔細研究過,所以不敢輕易評論). 
mootools 
現(xiàn)在來看看在 moo的幫助下如何去定義一個類: 
java代碼
var personclass = new class( {	initialize: function(name,gender){		this.name=name;		this.gender=gender;		alert("my name is "+this.name);	}});var mygirlfriend=new personclass('vickey','female');
其中類的 initialize 不是必須的. 
如果你想給 personclass 增加屬性和方法,你可以在new class的參數(shù)里直接以 json方式定義. 
也可以使用 如下方式 
java代碼
personclass.implement ({ 	age:0 ,	getname : function() {return this.name;}} , {...}, ..... );
implement支持多個{}.關于implement稍后在對比繼承機制時再細說. 
|||
在來看一下moo類機制的一些核心代碼. 
java代碼
var class = function(properties){	var klass = function(){		return (arguments[0] !== null && this.initialize && $type(this.initialize) == 'function') ? this.initialize.apply(this, arguments) : this;	};	$extend(klass, this);	klass.prototype = properties;	klass.constructor = class;	return klass;};class.prototype = {	extend: function(properties){		var proto = new this(null);		for (var property in properties){			var pp = proto[property];			proto[property] = class.merge(pp, properties[property]);		}		return new class(proto);	},	implement: function(){		for (var i = 0, l = arguments.length; i < l; i++) $extend(this.prototype, arguments[i]);	}};代碼的具體原理就不細說了.大家在moo的class里看到了 extend 和implement,那下面就來具體說一說moo和prototype的 繼承機制吧. 
=========================================== 
二. 繼承機制 
=========================================== 
prototype 
prototype提供的繼承很簡單. 
java代碼
object.extend = function(destination, source) {  for (var property in source) {    destination[property] = source[property];  }  return destination;}他只是把source里的屬性賦給destination,同時會覆蓋destination里的同名屬性. 
他可以用于對象,也可以用于類,當要實現(xiàn)類的繼承時,destination要使用 mysubclass.prototype. 
prototype的繼承機制可以說是非常薄弱的. 
mootools 
moo提供了三種繼承機制: 
首先他也提供了簡單的繼承機制: 
objcet.extend (注意,不是上面代碼中 class 里的 extend) 
他的代碼如下 
java代碼
var $extend = function(){	var args = arguments;	if (!args[1]) args = [this, args[0]];	for (var property in args[1]) args[0][property] = args[1][property];	return args[0];};object.extend = $extend;
他的使用方法和 prototype 完全一樣. 
但是大家可能注意到了 這句 if (!args[1]) args = [this, args[0]]; 這句的純在使得下面的代碼寫法成為可能. 
java代碼
var myobjcet={....};myobjcet.extend=$extend;myobjcet.extend(obja);myobjcet.extend(objb);myobjcet.extend(objc);簡單的一句話,讓extend的用法增加了更多的靈活性,不得不贊一個了!!!
|||
下面說說重點, moo的類里的extend和 implement 
先說 implement,之前已經(jīng)說了一些了 
java代碼
var myclassa = new class();myclassa.implement( { methoda : function() {... } }  );執(zhí)行后 myclassa 將擁有 methoda. 
implement用來向類中添加屬性和方法(會覆蓋同名屬性和方法),相當于 
object.extend (myclassa.prototype , {... } ) 
但是object.extend 不支持多個source,implement可以,示例如下: 
myclassa.implement( obja , objb, objc ... ); 
下面來看看moo的class.extend. 
moo的class.extend才是我們期待的真正的"類繼承",看一下官方的示例 
java代碼
		var animal = new class({			initialize: function(age){				this.age = age;			}		});		var cat = animal.extend({			initialize: function(name, age){				this.parent(age); //will call the previous initialize;				this.name = name;			}		});看那個parent() !!!! 
通過moo的class.extend實現(xiàn)的繼承提供一個關鍵的方法 parent(). 
使用他你可以調(diào)用父類中的同名方法,好像java里的super一樣. 
這個示例已經(jīng)可以說明一切了. 
關于prototype和moo的類機制和繼承機制的對比就到這里,孰優(yōu)孰劣大家心里應該有數(shù)了吧. 
=========================================== 
三.抽象對象 
=========================================== 
再來看一看"抽象對象". 這個雖然對于開發(fā)人員來說用處不大,但還是對比一下吧,小細節(jié)也能看出作者的用心. 
prototype 
prototype的抽象對象很簡單 
var abstract = new object(); 
具體的意義不大. 
mootools 
moo的的抽象對象相對更完善一些. 
java代碼
var abstract = function(obj){	obj = obj || {};	obj.extend = $extend;	return obj;};
支持自定義抽象(以參數(shù)形式傳入),同時會為抽象對象自動添加extend方法. 
=========================================== 
四. 關于 $() 
=========================================== 
prototype 
prototype的$大家都比較熟悉了, 工作原理就是 
通過id取得一個頁面元素(或者直接傳入一個頁面元素對象),然后給他增加一些prototype提供的方法和屬性,來方便開發(fā)人員對頁面元素的使用. 
mootools 
moo在這方面做的差不多. 
不同的主要有兩點, 首先moo為頁面元素增加的方法和屬性與prototype的不同(這個稍后會介紹),另外一個不同是moo的$兼具了對象管理的一個功能. 
他引入了一個  garbage 類, 來對頁面元素進行一個統(tǒng)一的管理和回收(主要是回收). 
可以更好的減少js(或瀏覽器)造成的內(nèi)存泄露等問題. 
具體的大家可以看一下代碼,在這里就不詳細說明了. 
|||
=========================================== 
五.關于 array enumerable hash 
=========================================== 
prototype 和 moo 都提供了集合迭代方法 (each) 
這個網(wǎng)上已經(jīng)有一篇不錯的對比文章,我就不在這里重復了 
http://blog.fackweb.cn/?p=50. 
moo的 foreach/each方法: function(fn, bind){..} 
那個bind 結合代碼 和 上面那篇文章, 大家應該可以很好的看出來prototype和moo的不同與優(yōu)劣. 
prototype里面有 enumerable 的概念,moo沒有. 
但是我個人一直覺得 enumerable 比較雞肋. 
在實際開發(fā)中,很少使用. 
enumerable的功能完全可以 用普通json對象 或者是 hash來實現(xiàn). 
moo的作者也許同樣這么認為.所以 不再 設置一個 雞肋的 enumerable類. 
但是請大家放心, enumerable 能做的事情, 在moo里也能完成. 
可以理解為 
moo的 array +  hash +{} 完全可以接替 prototype的 array + enumerable + hash +{} 
當然對于一些工具方法兩者提供的都不太一樣,不好比較,但是那些方法都是附屬品. 
我們完全可以自己來實現(xiàn),所以不在這次的比較范疇之內(nèi). 
=========================================== 
六. 關于 element 
=========================================== 
兩者的 element 從作用上看類似.都是一種對頁面元素的包裝,為頁面元素添加了一些諸如 addevent remove style之類的方法. 
但是大家通過看代碼可以發(fā)現(xiàn) moo的實現(xiàn)明顯更簡潔 更oo. 
同時還有一個關鍵的不同,prototype又提取出了一個form對象,里面包含了很多表單相關的方法. 
同時還衍生出了 serializeelements method 等等很多類和方法,代碼瞬間變得異常復雜和難以琢磨. 
而moo中沒有form對象,在moo中,form本身就是一個element 他沒什么特別的,這樣的思想類似components模式 
普通element具備的方法 form 都應該具備, form具備的方法 element也都應該包含.form 和 其他頁面元素沒什么不同. 
form元素只是一個包含了 input select textarea等子元素,同時擁有action target等屬性而已. 
一個p 一個span 一個td... 同樣可以包含input select textarea子元素,同樣可以擁有.action target屬性. 
瀏覽器處理他們的方式可能不同,但是在moo面前,大家完全平等. 
其實prototype里 form和普通頁面元素幾乎也是平等的,但是問題就是,既然是平等的,又何必硬生生的造出form以及那么多的衍生物呢? 
=========================================== 
七.ajax 
=========================================== 
prototype 
prototype的ajax實現(xiàn)主要是靠一個 ajax類 來實現(xiàn).(但是這個類形同虛設,大家更多的是和 ajax.request 類打交道. 
先來看一個prototype下一個簡單的ajax提交實例: 
java代碼
var myajax = new ajax.request( url,{parameters: mydata , oncomplete: callbackfunction } );
其中 mydata 可以是字符 : "name=vickey&gender=female"; 
也可以是對象 { name : vickey, gender : female } 
mootools 
moo首先在將ajax機制分層.提取出了一個基類:xhr. 
目前xhr有兩個子類, 一個是 ajax ,另一個是json.remote. 
在moo下一個簡單的ajax提交實例: 
java代碼
 var myajax =new ajax(url, {data : mydata , oncomplete: callbackfunction  }).request();
大家可以看到request成為了ajax對象的一個方法,這樣的設計顯然是更合理更自然 也更oo的. 
而且關鍵的一點是,你可以提前創(chuàng)建好你需要的ajax對象.在需要發(fā)出請求時再發(fā)出請求. 
java代碼
var myajax =new ajax(...);..... myajax.request();
同時還有一個重要特性, request是支持參數(shù)的,這個參數(shù)就是你要提交的數(shù)據(jù). 
也就是說,你可以在new ajax時不指定數(shù)據(jù)或者指定一個默認數(shù)據(jù). 
在提交的時候可以提交另一個data.如. 
myajax.request(yourdata); 
其中data可以是字符串,可以是對象, 也可以是一個頁面元素. 
要用ajax提交一個form 或者一個 p下的所有表單元素,只是改變一下 mydata. 
var mydata= $("formid");  // var mydata= $("pid"); 
然后就和普通的ajax提交完全一樣了. 
myajax.request(mydata); 
當然還有更oo的方式 : 
mydata.send({oncomplete: callbackfunction }); 
用后一種方式的時候要保證提交的元素有action屬性,沒有你就賦一個 mydata.action=url. 
prototype里如何實現(xiàn)這一功能呢?? 
prototype 
form.request($("formid") ,{ oncomplete: callbackfunction }); 
當然prototype里也可以類似moo的做法 , 只要讓mydata=$("formid").serialize(true) 就可以了. 
但是這一個小小的不同,反映出了設計上的差距. 
mootools 
moo的json.remote類,簡單,但是很實用: 
java代碼
	var jsonremoterequest = new json.remote( url , {oncomplete:callbackfunction }).send({name: 'vickey',gender: 'female' });
這個類和ajax類的本質(zhì)區(qū)別是, 
他提交的是一個序列化后的 json字符串("{name: 'vickey',gender: 'female' } "),而不是把 json對象轉化成querystring ("name=vickey&gender=female"); 
=========================================== 
結束語 
=========================================== 
寫這篇文章不是要批評prototype,以我現(xiàn)在的水平還沒那個資格. 
只是和mootools對比后, prototype在設計上的不足立刻就顯現(xiàn)了出來. 
雖然prototype新版本變化很多,很多我上面提到的一些不足都改正了,而且也加入了很多以前不具備的新的特性. 
但是prototype現(xiàn)在的發(fā)展停留在:"修補不足,增加功能"的階段,而沒有從設計上進行深層次的重構,所以我不認為他在mootools面前有足夠的底氣. 
至于jquery我沒有深入研究過,但是它的設計覺得完全是prototype風格的, 注意,我說的是設計風格,而不是代碼風格. 
代碼上他可能寫的更精妙,更有趣,但是設計上依然是prototype風格:薄弱的類機制,靠簡單的extend支撐起整個系統(tǒng). 
jquery在很多方面很出色,但是歸根結底他和prototype走在一條路上,只是在有些方面他走的更快. 
mootools并非完美無缺,但是至少現(xiàn)在他美的地方比prototype更多,缺的地方比prototype更少. 
所以,我選擇mootools. 你呢?? 
不要聽評論,不要看介紹, 只要看看他們的源代碼, 同時動手用他們寫些東西, 你的答案自然會浮現(xiàn)出來. 
新聞熱點
疑難解答
圖片精選