prototype 源码中文说明之 prototype.js

时间:2021-05-26

/**
*定义一个全局对象,属性Version在发布的时候会替换为当前版本号
*/
varPrototype={
Version:'@@VERSION@@'
}

/**
*创建一种类型,注意其属性create是一个方法,返回一个构造函数。
*一般使用如下
*varX=Class.create();返回一个类型,类似于java的一个Class实例。
*要使用X类型,需继续用newX()来获取一个实例,如同java的Class.newInstance()方法。
*
*返回的构造函数会执行名为initialize的方法,initialize是Ruby对象的构造器方法名字。
*此时initialize方法还没有定义,其后的代码中创建新类型时会建立相应的同名方法。
*
*如果一定要从java上去理解。你可以理解为用Class.create()创建一个继承java.lang.Class类的类。当然java不允许这样做,因为Class类是final的
*
*/
varClass={
create:function(){
returnfunction(){
this.initialize.apply(this,arguments);
}
}
}

/**
*创建一个对象,从变量名来思考,本意也许是定义一个抽象类,以后创建新对象都extend它。
*但从其后代码的应用来看,Abstract更多是为了保持命名空间清晰的考虑。
*也就是说,我们可以给Abstract这个对象实例添加新的对象定义。
*
*从java去理解,就是动态给一个对象创建内部类。
*/
varAbstract=newObject();

/**
*获取参数对象的所有属性和方法,有点象多重继承。但是这种继承是动态获得的。
*如:
*vara=newObjectA(),b=newObjectB();
*varc=a.extend(b);
*此时c对象同时拥有a和b对象的属性和方法。但是与多重继承不同的是,cinstanceofObjectB将返回false。
*/
Object.prototype.extend=function(object){
for(propertyinobject){
this[property]=object[property];
}
returnthis;
}

/**
*这个方法很有趣,它封装一个javascript函数对象,返回一个新函数对象,新函数对象的主体和原对象相同,但是bind()方法参数将被用作当前对象的对象。
*也就是说新函数中的this引用被改变为参数提供的对象。
*比如:
*<inputtype="text"id="aaa"value="aaa">
*<inputtype="text"id="bbb"value="bbb">
*.................
*<script>
*varaaa=document.getElementById("aaa");
*varbbb=document.getElementById("bbb");
*aaa.showValue=function(){alert(this.value);}
*aaa.showValue2=aaa.showValue.bind(bbb);
*</script>
*那么,调用aaa.showValue将返回"aaa",但调用aaa.showValue2将返回"bbb"。
*
*apply是ie5.5后才出现的新方法(Netscape好像很早就支持了)。
*该方法更多的资料参考MSDNhttp://msdn.microsoft.com/library/en-us/script56/html/js56jsmthApply.asp
*还有一个call方法,应用起来和apply类似。可以一起研究下。
*/
Function.prototype.bind=function(object){
varmethod=this;
returnfunction(){
method.apply(object,arguments);
}
}

/**
*和bind一样,不过这个方法一般用做html控件对象的事件处理。所以要传递event对象
*注意这时候,用到了Function.call。它与Function.apply的不同好像仅仅是对参数形式的定义。
*如同java两个过载的方法。
*/
Function.prototype.bindAsEventListener=function(object){
varmethod=this;
returnfunction(event){
method.call(object,event||window.event);
}
}

/**
*将整数形式RGB颜色值转换为HEX形式
*/
Number.prototype.toColorPart=function(){
vardigits=this.toString(16);
if(this<16)return'0'+digits;
returndigits;
}

/**
*典型Ruby风格的函数,将参数中的方法逐个调用,返回第一个成功执行的方法的返回值
*/
varTry={
these:function(){
varreturnValue;

for(vari=0;i<arguments.length;i++){
varlambda=arguments[i];
try{
returnValue=lambda();
break;
}catch(e){}
}

returnreturnValue;
}
}



/**
*一个设计精巧的定时执行器
*首先由Class.create()创建一个PeriodicalExecuter类型,
*然后用对象直接量的语法形式设置原型。
*
*需要特别说明的是rgisterCallback方法,它调用上面定义的函数原型方法bind,并传递自己为参数。
*之所以这样做,是因为setTimeout默认总以window对象为当前对象,也就是说,如果registerCallback方法定义如下的话:
*registerCallback:function(){
*setTimeout(this.onTimerEvent,this.frequency*1000);
*}
*那么,this.onTimeoutEvent方法执行失败,因为它无法访问this.currentlyExecuting属性。
*而使用了bind以后,该方法才能正确的找到this,也就是PeriodicalExecuter的当前实例。
*/
varPeriodicalExecuter=Class.create();
PeriodicalExecuter.prototype={
initialize:function(callback,frequency){
this.callback=callback;
this.frequency=frequency;
this.currentlyExecuting=false;

this.registerCallback();
},

registerCallback:function(){
setTimeout(this.onTimerEvent.bind(this),this.frequency*1000);
},

onTimerEvent:function(){
if(!this.currentlyExecuting){
try{
this.currentlyExecuting=true;
this.callback();
}finally{
this.currentlyExecuting=false;
}
}

this.registerCallback();
}
}



/**
*这个函数就Ruby了。我觉得它的作用主要有两个
*1.大概是document.getElementById(id)的最简化调用。
*比如:$("aaa")将返回上aaa对象
*2.得到对象数组
*比如:$("aaa","bbb")返回一个包括id为"aaa"和"bbb"两个input控件对象的数组。
*/
function$(){
varelements=newArray();

for(vari=0;i<arguments.length;i++){
varelement=arguments[i];
if(typeofelement=='string')
element=document.getElementById(element);

if(arguments.length==1)
returnelement;

elements.push(element);
}

returnelements;
}
/**
*定义Ajax对象,静态方法getTransport方法返回一个XMLHttp对象
*/
varAjax={
getTransport:function(){
returnTry.these(
function(){returnnewActiveXObject('Msxml2.XMLHTTP')},
function(){returnnewActiveXObject('Microsoft.XMLHTTP')},
function(){returnnewXMLHttpRequest()}
)||false;
},

emptyFunction:function(){}
}

/**
*我以为此时的Ajax对象起到命名空间的作用。
*Ajax.Base声明为一个基础对象类型
*注意Ajax.Base并没有使用Class.create()的方式来创建,我想是因为作者并不希望Ajax.Base被库使用者实例化。
*作者在其他对象类型的声明中,将会继承于它。
*就好像java中的私有抽象类
*/
Ajax.Base=function(){};
Ajax.Base.prototype={
/**
*extend(见prototype.js中的定义)的用法真是让人耳目一新
*options首先设置默认属性,然后再extend参数对象,那么参数对象中也有同名的属性,那么就覆盖默认属性值。
*想想如果我写这样的实现,应该类似如下:
setOptions:function(options){
this.options.methed=options.methed?options.methed:'post';
..........
}
我想很多时候,java限制了js的创意。
*/
setOptions:function(options){
this.options={
method:'post',
asynchronous:true,
parameters:''
}.extend(options||{});
}
}

/**
*Ajax.Request封装XmlHttp
*/
Ajax.Request=Class.create();

/**
*定义四种事件(状态),参考http://msdn.microsoft.com/workshop/author/dhtml/reference/properties/readystate_1.asp
*/
Ajax.Request.Events=
['Uninitialized','Loading','Loaded','Interactive','Complete'];

/**
*
*/
Ajax.Request.prototype=(newAjax.Base()).extend({
initialize:function(url,options){
this.transport=Ajax.getTransport();
this.setOptions(options);

try{
if(this.options.method=='get')
url+='?'+this.options.parameters+'&_=';

/**
*此处好像强制使用了异步方式,而不是依照this.options.asynchronous的值
*/
this.transport.open(this.options.method,url,true);

/**
*这里提供了XmlHttp传输过程中每个步骤的回调函数
*/
if(this.options.asynchronous){
this.transport.onreadystatechange=this.onStateChange.bind(this);
setTimeout((function(){this.respondToReadyState(1)}).bind(this),10);
}

this.transport.setRequestHeader('X-Requested-With','XMLHttpRequest');
this.transport.setRequestHeader('X-Prototype-Version',Prototype.Version);

if(this.options.method=='post'){
this.transport.setRequestHeader('Connection','close');
this.transport.setRequestHeader('Content-type',
'application/x-/workshop/author/dhtml/reference/methods/insertadjacenthtml.asp)
*这里算是一个对象形式的封装。
*/
Abstract.Insertion=function(adjacency){
this.adjacency=adjacency;
}

Abstract.Insertion.prototype={
initialize:function(element,content){
this.element=$(element);
this.content=content;

if(this.adjacency&&this.element.insertAdjacentHTML){
this.element.insertAdjacentHTML(this.adjacency,this.content);
}else{
/**
*gecko不支持insertAdjacentHTML方法,但可以用如下代码代替
*/
this.range=this.element.ownerDocument.createRange();
/**
*如果定义了initializeRange方法,则实行,这里相当与定义了一个抽象的initializeRange方法
*/
if(this.initializeRange)this.initializeRange();
this.fragment=this.range.createContextualFragment(this.content);

/**
*insertContent也是一个抽象方法,子类必须实现
*/
this.insertContent();
}
}
}

/**
*prototype加深了我的体会,就是写js如何去遵循 Don'tRepeatYourself(DRY)原则
*上文中Abstract.Insertion算是一个抽象类,定义了名为 initializeRange的一个抽象方法
*varInsertion=newObject() 建立一个命名空间
*Insertion.Before|Top|Bottom|After就象是四个java中的四个静态内部类,而它们分别继承于Abstract.Insertion,并实现了initializeRange方法。
*/
varInsertion=newObject();

Insertion.Before=Class.create();
Insertion.Before.prototype=(newAbstract.Insertion('beforeBegin')).extend({
initializeRange:function(){
this.range.setStartBefore(this.element);
},

/**
*将内容插入到指定节点的前面,与指定节点同级
*/
insertContent:function(){
this.element.parentNode.insertBefore(this.fragment,this.element);
}
});

Insertion.Top=Class.create();
Insertion.Top.prototype=(newAbstract.Insertion('afterBegin')).extend({
initializeRange:function(){
this.range.selectNodeContents(this.element);
this.range.collapse(true);
},

/**
*将内容插入到指定节点的第一个子节点前,于是内容变为该节点的第一个子节点
*/
insertContent:function(){
this.element.insertBefore(this.fragment,this.element.firstChild);
}
});

Insertion.Bottom=Class.create();
Insertion.Bottom.prototype=(newAbstract.Insertion('beforeEnd')).extend({
initializeRange:function(){
this.range.selectNodeContents(this.element);
this.range.collapse(this.element);
},

/**
*将内容插入到指定节点的最后,于是内容变为该节点的最后一个子节点
*/
insertContent:function(){
this.element.appendChild(this.fragment);
}
});

Insertion.After=Class.create();
Insertion.After.prototype=(newAbstract.Insertion('afterEnd')).extend({
initializeRange:function(){
this.range.setStartAfter(this.element);
},

/**
*将内容插入到指定节点的后面,与指定节点同级
*/
insertContent:function(){
this.element.parentNode.insertBefore(this.fragment,
this.element.nextSibling);
}
});



if(!Function.prototype.apply){
Function.prototype.apply=function(object,parameters){
varparameterStrings=newArray();
if(!object)object=window;
if(!parameters)parameters=newArray();

for(vari=0;i<parameters.length;i++)
parameterStrings[i]='parameters['+i+']';

object.__apply__=this;
varresult=eval('object.__apply__('+parameterStrings.join(',')+')');
object.__apply__=null;

returnresult;
}
}

Effect的一个子类




Effect.Blink=Class.create();
Effect.Blink.prototype={
initialize:function(element,frequency){
this.element=$(element);
this.frequency=frequency?frequency:1000;
this.element.effect_blink=this;
this.blink();
},

blink:function(){
if(this.timer)clearTimeout(this.timer);
try{
this.element.style.visibility=this.element.style.visibility=='hidden'?'visible':'hidden';
}catch(e){}
this.timer=setTimeout(this.blink.bind(this),this.frequency);
}
};

声明:本页内容来源网络,仅供用户参考;我单位不保证亦不表示资料全面及准确无误,也不保证亦不表示这些资料为最新信息,如因任何原因,本网内容或者用户因倚赖本网内容造成任何损失或损害,我单位将不会负任何法律责任。如涉及版权问题,请提交至online#300.cn邮箱联系删除。

相关文章