prototype.js在Class.create,bind等中用到javascript的闭包特色。但整体上prototype.js对于强大的闭包特性用的不多。大家可以参阅我翻译的篇文章了解闭包。
3、让我比较反感的两个方法
(1)
var Class = {
create: function() {
return function() {
this.initialize.apply(this, arguments);
}
}
}
其实讨厌这条有些牵强,不过修改Object的原型对象就有点过分了。
(2)Object.prototype.extend
先不过你取个extend的名字会让熟悉java的人引起的歧义。修改Object的prototype就说不过去了。不知道作者是怎么考虑的。当你for in循环对象是,麻烦就来了。可能有人会问你for in干吗。 我一个项目中既用了DWR,也用了prototype.js,dwr返回的javascript对象都多了个exetend属性,还得特殊处理。
以前我比较过dojo和prototype.js中继承的实现,现在我明白个道理。对于javascript这种没有静态类型检查,语法宽松的语言来讲,如果你选择了某个js类库,那你也必须适应作者写javascript的风格。prototype.js的作者对extend的使用炉火纯青,如果我们不当它只是个属性拷贝的函数的话,多读读prototype.js的代码是好的。
关于事件的注册
<script src="prototype1.3.1.js"></script>
<input type=checkbox id=myChk name="chk" value=1> Test
<script>
Event.observe(myChk, 'click', showMessage, false);
//$('myChk').onclick=showMessage;
//$('myChk').onclick=showMessage.bind();
$('myChk').onclick=showMessage.bind($('myChk'));
function showMessage() {
alert(this.value);
}
</script>
(1) 显然Event.observe有限制,只能处理简单的函数,并函数中不能有this之类的东西。
(2)Event.observe内部用到addEventListener/attachEvent。能把多个函数加到一个触发事件(window.onload)。bind是覆盖。
关于函数的绑定
类库提供了Function.prototype.bind Function.prototype.bindAsEventListener两个方法。首先我们从概念上解释一个这两个方法。
任何一个函数都可以调用这两个方法;参数的是javascript对象或网页上元素对象;返回类型是个函数对象。
本来我就是个函数,返回还是函数,到这两个函数有什么不同呢。看实现代码,关键还是apply\call函数的代码。其实这里只是转化了一下方法调用的对象。
<script src="prototype1.3.1.js"></script>
<input type=checkbox id=myChk name="asf" value=1> Test
<script>
var CheckboxWatcher = Class.create();
CheckboxWatcher.prototype = {
initialize: function(chkBox, message) {
this.chkBox = $(chkBox);
this.message = message;
this.chkBox.onclick = this.showMessage.bindAsEventListener(this);
},
showMessage: function(evt) {
alert(this.message + ' (' + evt.type + ')');
}
};
new CheckboxWatcher('myChk','message!!!!');
//$('myChk').onclick=function(){};
</script>
看下面代码:
<script src="prototype1.3.1.js"></script>
<input type=checkbox id=myChk name="chk" value=1> Test
<script>
function Class(){
this.name="class";
}
Class.prototype.getName=function(){
alert(this.name);
}
var obj=new Class();
//$('myChk').onclick=obj.getName;
$('myChk').onclick=obj.getName.bind(obj);
//$('myChk').onclick=obj.getName.bind($('myChk'));
</script>
这两个方法也可以用在对象之间的方法重用,实现类似继承方法的概念。看以下代码,其实是比较无聊的。
<script src="prototype1.3.1.js"></script>
<script>
function Class1(name){
this.name=name;
}
Class1.prototype.getName=function(){
alert(this.name);
}
function Class2(name){
this.name=name;
this.getName=Class1.prototype.getName.bind(this);
}
var obj1=new Class2("yql");
obj1.getName();
var obj2=new Object();
obj2.name="zkj";
obj2.fun=Class1.prototype.getName.bind(obj2);
obj2.fun();
</script>
关于事件监听最佳实践
很显然prototype.js提供的事件注册方法不是很完善。那看看dojo的时间注册吧(中文版),更加复杂,估计很多人像我一样,对于dojo暂时持观望态度。
如果你看过的前篇关于闭包的介绍,可能见过以下代码。
看以下代码前我想表述一个观点,任何网页中元素,浏览器都会为你创建一个对象(见)。(我觉得)这些对象与你建立javascript对象区别是它们有事件监听,会响应鼠标键盘的事件。如果你用了以下代码,那么把事件监听代码很好的转化到你的javascript代码中。
function associateObjWithEvent(obj, methodName){
return (function(e){
e = e||window.event;
return obj[methodName](e, this);
});
}
function DhtmlObject(elementId){
var el = getElementWithId(elementId);
if(el){
el.onclick = associateObjWithEvent(this, "doOnClick");
el.onmouseover = associateObjWithEvent(this, "doMouseOver");
el.onmouseout = associateObjWithEvent(this, "doMouseOut");
}
}
DhtmlObject.prototype.doOnClick = function(event, element){
... // doOnClick method body.
}
DhtmlObject.prototype.doMouseOver = function(event, element){
... // doMouseOver method body.
}
DhtmlObject.prototype.doMouseOut = function(event, element){
... // doMouseOut method body.
}