首页 > 开发 > 综合 > 正文

MooTools教程(告诉你为什么学Mootools)

2024-07-21 02:04:36
字体:
来源:转载
供稿:网友

mootools是一个简洁,模块化,面向对象的javascript框架。它能够帮助你更快,更简单地编写可扩展和兼容性强的javascript代码。mootools跟prototypejs相类似,语法几乎一样。但它提供的功能要比prototypejs多,而且更强大。比如增加了动画特效、拖放操作等等。建议大家可以用它来代替prototypejs。

我为什么选择mootools,抛弃了prototype. (mootools 与 prototype 核心代码分析)

===========================================
前言
===========================================

最近喜欢上了mootools(相见恨晚啊),在公开表示了对他的偏爱.
很多朋友都问我为什么要移情别恋,其实理由还是蛮多的.

今天在这里打算列举出一部分.让更多的朋友能够了解一下mootools,也希望有更多的朋友喜欢上他.

文章的标题注定了我会更多的讲述 mootools比prototype好的地方,
希望大家不要被我的误导,以为mootools处处都比prototype好.
mootools还是有一些不足的.

本次对比针对 mootools 1.11版 和 prototype 1.51版,
只比较了一些核心代码,其他的工具方法,辅助函数不再本文讨论之内.

开始前,再次重申一遍:我曾经很爱prototype,而且我将永远都会用"伟大"来形容它.

好 下面对比正式开始 (
mootools以下简称moo.
本文所引用的代码, 只是起到说明作用,不保证他们都可以被正确的执行.
同时为了使本文简洁一些,引入的 一些 moo和prototype的代码也只是片段或是伪代码.
)

===========================================
一. 类机制
===========================================

js里的类实际上就是function.
如果不使用任何框架和组件,那么想创建一个自己类也不是难事,方法如下:

 

 

java代码

 

  1. var personclass=function(name,gender){   
  2.     this.name=name;   
  3.     this.gender=gender;   
  4.     alert("my name is "+this.name);   
  5. }   
  6.   
  7. var mygirlfriend=new personclass('vickey','female');  

 

var personclass=function(name,gender){	this.name=name;	this.gender=gender;	alert("my name is "+this.name);}var mygirlfriend=new personclass('vickey','female');

执行 后, 会创建一个personclass类的实例mygirlfriend, 并执行function内的语句.
那些语句可以理解为是类的构造函数.

prototype
现在来看看在prototype的帮助下如何去定义这个类:

 

 

java代码

 

  1. var personclass = class.create();   
  2.   
  3. personclass.prototype.initialize=function(name,gender){   
  4.     this.name=name;   
  5.     this.gender=gender;   
  6.     alert("my name is "+this.name);   
  7. };   
  8.   
  9. var mygirlfriend=new personclass('vickey','female');   
  10.   
  11. //如果想给类增加属性和方法时使用    
  12. personclass.prototype.xxx=...;   
  13. //或者是使用 prototype提供的    
  14. object.extend(personclass.prototype, {...} );  

 

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是实现类机制的核心代码.

 

 

java代码

 

  1. var class = {   
  2.   create: function() {   
  3.     return function() {   
  4.       this.initialize.apply(this, arguments);   
  5.     }   
  6.   }   
  7. }  

 

var class = {  create: function() {    return function() {      this.initialize.apply(this, arguments);    }  }}


通过看代码不难看出,prototype的class实际上只是帮助我们抽象出了"类的构造函数".
而当我们在prototype的这种机制下进行类的定义时,实际上带来的好处是非常有限的.
prototype的class只是从结构对我们的类进行了重新规划. 而这样的规划意义并不是很大.
而且prototype带有强制性,即, initialize 是必须要定义的.
实际上这里存在一个缺陷, class应该提供一个默认的initialize(一个空函数就好),
或者是在create返回的function里进行必要的判断.
(prototype1.6的类机制变化比较大,但是还没仔细研究过,所以不敢轻易评论).

mootools

现在来看看在 moo的帮助下如何去定义一个类:

 

 

java代码

 

  1. var personclass = new class( {   
  2.     initialize: function(name,gender){   
  3.         this.name=name;   
  4.         this.gender=gender;   
  5.         alert("my name is "+this.name);   
  6.     }   
  7. });   
  8. var mygirlfriend=new personclass('vickey','female');  

 

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的参数里直接以 json方式定义.
也可以使用 如下方式

 

 

java代码

 

  1. personclass.implement ({    
  2.     age:0 ,   
  3.     getname : function() {return this.name;}   
  4. } , {...}, ..... );  

 

personclass.implement ({ 	age:0 ,	getname : function() {return this.name;}} , {...}, ..... );


implement支持多个{}.关于implement稍后在对比继承机制时再细说.

|||

在来看一下moo类机制的一些核心代码.

 

 

java代码

 

  1. var class = function(properties){   
  2.     var klass = function(){   
  3.         return (arguments[0] !== null && this.initialize && $type(this.initialize) == 'function') ? this.initialize.apply(this, arguments) : this;   
  4.     };   
  5.     $extend(klass, this);   
  6.     klass.prototype = properties;   
  7.     klass.constructor = class;   
  8.     return klass;   
  9. };   
  10.   
  11. class.prototype = {   
  12.     extend: function(properties){   
  13.         var proto = new this(null);   
  14.         for (var property in properties){   
  15.             var pp = proto[property];   
  16.             proto[property] = class.merge(pp, properties[property]);   
  17.         }   
  18.         return new class(proto);   
  19.     },   
  20.     implement: function(){   
  21.         for (var i = 0, l = arguments.length; i < l; i++) $extend(this.prototype, arguments[i]);   
  22.     }   
  23.   
  24. };  

 

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代码

 

  1. object.extend = function(destination, source) {   
  2.   for (var property in source) {   
  3.     destination[property] = source[property];   
  4.   }   
  5.   return destination;   
  6. }  

 

object.extend = function(destination, source) {  for (var property in source) {    destination[property] = source[property];  }  return destination;}

他只是把source里的属性赋给destination,同时会覆盖destination里的同名属性.
他可以用于对象,也可以用于类,当要实现类的继承时,destination要使用 mysubclass.prototype.

prototype的继承机制可以说是非常薄弱的.

mootools

moo提供了三种继承机制:

首先他也提供了简单的继承机制:
objcet.extend (注意,不是上面代码中 class 里的 extend)
他的代码如下

 

 

java代码

 

  1.   
  2. var $extend = function(){   
  3.     var args = arguments;   
  4.     if (!args[1]) args = [this, args[0]];   
  5.     for (var property in args[1]) args[0][property] = args[1][property];   
  6.     return args[0];   
  7. };   
  8. object.extend = $extend;  

 

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代码

 

  1. var myobjcet={....};   
  2. myobjcet.extend=$extend;   
  3. myobjcet.extend(obja);   
  4. myobjcet.extend(objb);   
  5. myobjcet.extend(objc);  

 

var myobjcet={....};myobjcet.extend=$extend;myobjcet.extend(obja);myobjcet.extend(objb);myobjcet.extend(objc);

简单的一句话,让extend的用法增加了更多的灵活性,不得不赞一个了!!!

|||

下面说说重点, moo的类里的extend和 implement
先说 implement,之前已经说了一些了

 

 

java代码

 

  1. var myclassa = new class();   
  2. myclassa.implement( { methoda : function() {... } }  );  

 

var myclassa = new class();myclassa.implement( { methoda : function() {... } }  );

执行后 myclassa 将拥有 methoda.

implement用来向类中添加属性和方法(会覆盖同名属性和方法),相当于
object.extend (myclassa.prototype , {... } )
但是object.extend 不支持多个source,implement可以,示例如下:
myclassa.implement( obja , objb, objc ... );

下面来看看moo的class.extend.
moo的class.extend才是我们期待的真正的"类继承",看一下官方的示例

 

 

java代码

 

  1. var animal = new class({   
  2.     initialize: function(age){   
  3.         this.age = age;   
  4.     }   
  5. });   
  6. var cat = animal.extend({   
  7.     initialize: function(name, age){   
  8.         this.parent(age); //will call the previous initialize;   
  9.         this.name = name;   
  10.     }   
  11. });  

 

		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实现的继承提供一个关键的方法 parent().
使用他你可以调用父类中的同名方法,好像java里的super一样.
这个示例已经可以说明一切了.

关于prototype和moo的类机制和继承机制的对比就到这里,孰优孰劣大家心里应该有数了吧.

===========================================
三.抽象对象
===========================================

再来看一看"抽象对象". 这个虽然对于开发人员来说用处不大,但还是对比一下吧,小细节也能看出作者的用心.

prototype
prototype的抽象对象很简单
var abstract = new object();
具体的意义不大.

mootools
moo的的抽象对象相对更完善一些.

 

 

java代码

 

  1. var abstract = function(obj){   
  2.     obj = obj || {};   
  3.     obj.extend = $extend;   
  4.     return obj;   
  5. };  

 

var abstract = function(obj){	obj = obj || {};	obj.extend = $extend;	return obj;};


支持自定义抽象(以参数形式传入),同时会为抽象对象自动添加extend方法.

===========================================
四. 关于 $()
===========================================

prototype
prototype的$大家都比较熟悉了, 工作原理就是
通过id取得一个页面元素(或者直接传入一个页面元素对象),然后给他增加一些prototype提供的方法和属性,来方便开发人员对页面元素的使用.

mootools
moo在这方面做的差不多.
不同的主要有两点, 首先moo为页面元素增加的方法和属性与prototype的不同(这个稍后会介绍),另外一个不同是moo的$兼具了对象管理的一个功能.
他引入了一个  garbage 类, 来对页面元素进行一个统一的管理和回收(主要是回收).
可以更好的减少js(或浏览器)造成的内存泄露等问题.

具体的大家可以看一下代码,在这里就不详细说明了.

|||

===========================================
五.关于 array enumerable hash
===========================================

prototype 和 moo 都提供了集合迭代方法 (each)
这个网上已经有一篇不错的对比文章,我就不在这里重复了
http://blog.fackweb.cn/?p=50.

moo的 foreach/each方法: function(fn, bind){..}
那个bind 结合代码 和 上面那篇文章, 大家应该可以很好的看出来prototype和moo的不同与优劣.

prototype里面有 enumerable 的概念,moo没有.
但是我个人一直觉得 enumerable 比较鸡肋.
在实际开发中,很少使用.
enumerable的功能完全可以 用普通json对象 或者是 hash来实现.
moo的作者也许同样这么认为.所以 不再 设置一个 鸡肋的 enumerable类.
但是请大家放心, enumerable 能做的事情, 在moo里也能完成.

可以理解为

moo的 array +  hash +{} 完全可以接替 prototype的 array + enumerable + hash +{}
当然对于一些工具方法两者提供的都不太一样,不好比较,但是那些方法都是附属品.
我们完全可以自己来实现,所以不在这次的比较范畴之内.

===========================================
六. 关于 element
===========================================

两者的 element 从作用上看类似.都是一种对页面元素的包装,为页面元素添加了一些诸如 addevent remove style之类的方法.
但是大家通过看代码可以发现 moo的实现明显更简洁 更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实现主要是靠一个 ajax类 来实现.(但是这个类形同虚设,大家更多的是和 ajax.request 类打交道.

先来看一个prototype下一个简单的ajax提交实例:

 

 

java代码

 

  1. var myajax = new ajax.request( url,{parameters: mydata , oncomplete: callbackfunction } );  

 

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代码

 

  1. var myajax =new ajax(url, {data : mydata , oncomplete: callbackfunction  }).request();  

 

 var myajax =new ajax(url, {data : mydata , oncomplete: callbackfunction  }).request();


大家可以看到request成为了ajax对象的一个方法,这样的设计显然是更合理更自然 也更oo的.

而且关键的一点是,你可以提前创建好你需要的ajax对象.在需要发出请求时再发出请求.

 

 

java代码

 

  1. var myajax =new ajax(...);   
  2. ....   
  3. myajax.request();  

 

 var myajax =new ajax(...);..... myajax.request();


同时还有一个重要特性, request是支持参数的,这个参数就是你要提交的数据.

也就是说,你可以在new ajax时不指定数据或者指定一个默认数据.
在提交的时候可以提交另一个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里如何实现这一功能呢??

prototype
form.request($("formid") ,{ oncomplete: callbackfunction });

当然prototype里也可以类似moo的做法 , 只要让mydata=$("formid").serialize(true) 就可以了.
但是这一个小小的不同,反映出了设计上的差距.

mootools
moo的json.remote类,简单,但是很实用:

 

 

java代码

 

  1. var jsonremoterequest = new json.remote( url , {oncomplete:callbackfunction }).send({name: 'vickey',gender: 'female' });  

 

	var jsonremoterequest = new json.remote( url , {oncomplete:callbackfunction }).send({name: 'vickey',gender: 'female' });


这个类和ajax类的本质区别是,
他提交的是一个序列化后的 json字符串("{name: 'vickey',gender: 'female' } "),而不是把 json对象转化成querystring ("name=vickey&gender=female");

===========================================
结束语
===========================================

写这篇文章不是要批评prototype,以我现在的水平还没那个资格.
只是和mootools对比后, prototype在设计上的不足立刻就显现了出来.

虽然prototype新版本变化很多,很多我上面提到的一些不足都改正了,而且也加入了很多以前不具备的新的特性.
但是prototype现在的发展停留在:"修补不足,增加功能"的阶段,而没有从设计上进行深层次的重构,所以我不认为他在mootools面前有足够的底气.

至于jquery我没有深入研究过,但是它的设计觉得完全是prototype风格的, 注意,我说的是设计风格,而不是代码风格.
代码上他可能写的更精妙,更有趣,但是设计上依然是prototype风格:薄弱的类机制,靠简单的extend支撑起整个系统.
jquery在很多方面很出色,但是归根结底他和prototype走在一条路上,只是在有些方面他走的更快.

mootools并非完美无缺,但是至少现在他美的地方比prototype更多,缺的地方比prototype更少.

所以,我选择mootools. 你呢??

不要听评论,不要看介绍, 只要看看他们的源代码, 同时动手用他们写些东西, 你的答案自然会浮现出来.

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表