【转】一个优秀的Javascript框架--Prototype解说
from:http://blog.csdn.net/meil/archive/2007/04/25/1585056.aspx
????? Prototype.js 是Ruby On Rails的副產品, Javascript編寫者的一把小軍刀,提供了Ruby風格的簡寫語法和實效的函數,更難得的是完全跨瀏覽器,讓大家舒舒服服寫出又精簡又不用愁心兼容的的JS代碼,SpringSide 已經離不開它了。
Prototype在線手冊
?*?定義一個全局對象,?屬性?Version?在發布的時候會替換為當前版本號?
?*/?
var?Prototype?=?{?
??Version:?'@@VERSION@@'?
}?
/**?
?*?創建一種類型,注意其屬性?create?是一個方法,返回一個構造函數。?
?*?一般使用如下??
?*?????var?X?=?Class.create();??返回一個類型,類似于?java?的一個Class實例。?
?*?要使用?X?類型,需繼續用?new?X()來獲取一個實例,如同?java?的?Class.newInstance()方法。?
?*?
?*?返回的構造函數會執行名為?initialize?的方法,?initialize?是?Ruby?對象的構造器方法名字。?
?*?此時initialize方法還沒有定義,其后的代碼中創建新類型時會建立相應的同名方法。?
?*?
?*?如果一定要從java上去理解。你可以理解為用Class.create()創建一個繼承java.lang.Class類的類。當然java不允許這樣做,因為Class類是final的?
?*?
?*/?
var?Class?=?{?
??create:?function()?{?
????return?function()?{?
??????this.initialize.apply(this,?arguments);?
????}?
??}?
}?
/**?
?*?創建一個對象,從變量名來思考,本意也許是定義一個抽象類,以后創建新對象都?extend?它。?
?*?但從其后代碼的應用來看,?Abstract?更多是為了保持命名空間清晰的考慮。?
?*?也就是說,我們可以給?Abstract?這個對象實例添加新的對象定義。?
?*?
?*?從java去理解,就是動態給一個對象創建內部類。?
?*/?
var?Abstract?=?new?Object();?
/**?
?*?獲取參數對象的所有屬性和方法,有點象多重繼承。但是這種繼承是動態獲得的。?
?*?如:?
?*?????var?a?=?new?ObjectA(),?b?=?new?ObjectB();?
?*?????var?c?=?a.extend(b);?
?*?此時?c?對象同時擁有?a?和?b?對象的屬性和方法。但是與多重繼承不同的是,c?instanceof?ObjectB?將返回false。?
?*/?
Object.prototype.extend?=?function(object)?{?
??for?(property?in?object)?{?
????this[property]?=?object[property];?
??}?
??return?this;?
}?
/**?
?*?這個方法很有趣,它封裝一個javascript函數對象,返回一個新函數對象,新函數對象的主體和原對象相同,但是bind()方法參數將被用作當前對象的對象。?
?*?也就是說新函數中的?this?引用被改變為參數提供的對象。?
?*?比如:?
?*?????<input?type="text"?id="aaa"?value="aaa">?
?*?????<input?type="text"?id="bbb"?value="bbb">?
?*?????..?
?*?????<script>?
?*?????????var?aaa?=?document.getElementById("aaa");?
?*?????????var?bbb?=?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好像很早就支持了)。?
?*?該方法更多的資料參考MSDN?http://msdn.microsoft.com/library/en-us/script56/html/js56jsmthApply.asp?
?*?還有一個?call?方法,應用起來和?apply?類似。可以一起研究下。?
?*/?
Function.prototype.bind?=?function(object)?{?
??var?method?=?this;?
??return?function()?{?
????method.apply(object,?arguments);?
??}?
}?
/**?
?*?和bind一樣,不過這個方法一般用做html控件對象的事件處理。所以要傳遞event對象?
?*?注意這時候,用到了?Function.call。它與?Function.apply?的不同好像僅僅是對參數形式的定義。?
?*?如同?java?兩個過載的方法。?
?*/?
Function.prototype.bindAsEventListener?=?function(object)?{?
??var?method?=?this;?
??return?function(event)?{?
????method.call(object,?event?||?window.event);?
??}?
}?
/**?
?*?將整數形式RGB顏色值轉換為HEX形式?
?*/?
Number.prototype.toColorPart?=?function()?{?
??var?digits?=?this.toString(16);?
??if?(this?<?16)?return?'0'?+?digits;?
??return?digits;?
}?
/**?
?*?典型?Ruby?風格的函數,將參數中的方法逐個調用,返回第一個成功執行的方法的返回值?
?*/?
var?Try?=?{?
??these:?function()?{?
????var?returnValue;?
????
????for?(var?i?=?0;?i?<?arguments.length;?i++)?{?
??????var?lambda?=?arguments[i];?
??????try?{?
????????returnValue?=?lambda();?
????????break;?
??????}?catch?(e)?{}?
????}?
????
????return?returnValue;?
??}?
}?
/*--------------------------------------------------------------------------*/?
/**?
?*?一個設計精巧的定時執行器?
?*?首先由?Class.create()?創建一個?PeriodicalExecuter?類型,?
?*?然后用對象直接量的語法形式設置原型。?
?*?
?*?需要特別說明的是?rgisterCallback?方法,它調用上面定義的函數原型方法bind,?并傳遞自己為參數。?
?*?之所以這樣做,是因為?setTimeout?默認總以?window?對象為當前對象,也就是說,如果?registerCallback?方法定義如下的話:?
?*?????registerCallback:?function()?{?
?*?????????setTimeout(this.onTimerEvent,?this.frequency?*?1000);?
?*?????}?
?*?那么,this.onTimeoutEvent?方法執行失敗,因為它無法訪問?this.currentlyExecuting?屬性。?
?*?而使用了bind以后,該方法才能正確的找到this,也就是PeriodicalExecuter的當前實例。?
?*/?
var?PeriodicalExecuter?=?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?$()?{?
??var?elements?=?new?Array();?
??
??for?(var?i?=?0;?i?<?arguments.length;?i++)?{?
????var?element?=?arguments[i];?
????if?(typeof?element?==?'string')?
??????element?=?document.getElementById(element);?
????if?(arguments.length?==?1)?
??????return?element;?
??????
????elements.push(element);?
??}?
??
??return?elements;?
}?
?
/**??*?定義?Ajax?對象,?靜態方法?getTransport?方法返回一個?XMLHttp?對象?
?*/?
var?Ajax?=?{?
??getTransport:?function()?{?
????return?Try.these(?
??????function()?{return?new?ActiveXObject('Msxml2.XMLHTTP')},?
??????function()?{return?new?ActiveXObject('Microsoft.XMLHTTP')},?
??????function()?{return?new?XMLHttpRequest()}?
????)?||?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?=?(new?Ajax.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-www-form-urlencoded');?
??????}?
??????
??????this.transport.send(this.options.method?==?'post'???
????????this.options.parameters?+?'&_='?:?null);?
??????????????????????
????}?catch?(e)?{?
????}????
??},?
??????
??onStateChange:?function()?{?
????var?readyState?=?this.transport.readyState;?
???/**?
????*?如果不是?Loading?狀態,就調用回調函數?
?????*/?
????if?(readyState?!=?1)?
??????this.respondToReadyState(this.transport.readyState);?
??},?
??
??/**?
???*?回調函數定義在?this.options?屬性中,比如:?
??????var?option?=?{?
?????????onLoaded?:?function(req)?{};?
??????????
??????}?
??????new?Ajax.Request(url,?option);?
???*/?
??respondToReadyState:?function(readyState)?{?
????var?event?=?Ajax.Request.Events[readyState];?
????(this.options['on'?+?event]?||?Ajax.emptyFunction)(this.transport);?
??}?
});?
/**?
?*?Ajax.Updater?用于綁定一個html元素與?XmlHttp調用的返回值。類似與?buffalo?的?bind。?
?*?如果?options?中有?insertion(from?dom.js)?對象的話,?insertion?能提供更多的插入控制。?
?*/?
Ajax.Updater?=?Class.create();?
Ajax.Updater.prototype?=?(new?Ajax.Base()).extend({?
??initialize:?function(container,?url,?options)?{?
????this.container?=?$(container);?
????this.setOptions(options);?
??
????if?(this.options.asynchronous)?{?
??????this.onComplete?=?this.options.onComplete;?
??????this.options.onComplete?=?this.updateContent.bind(this);?
????}?
????
????this.request?=?new?Ajax.Request(url,?this.options);?
????
????if?(!this.options.asynchronous)?
??????this.updateContent();?
??},?
??
??updateContent:?function()?{?
????if?(this.options.insertion)?{?
??????new?this.options.insertion(this.container,?
????????this.request.transport.responseText);?
????}?else?{?
??????this.container.innerHTML?=?this.request.transport.responseText;?
????}?
????if?(this.onComplete)?{?
??????setTimeout((function()?{this.onComplete(this.request)}).bind(this),?10);?
????}?
??}?
});?
?
/**??*?針對?頁面元素對象?的工具類,提供一些簡單靜態方法?
?*/?
var?Field?=?{?
??/**?
???*?清除參數引用對象的值?
???*/?
??clear:?function()?{?
????for?(var?i?=?0;?i?<?arguments.length;?i++)?
??????$(arguments[i]).value?=?'';?
??},?
??/**?
???*?使參數引用對象獲取焦點?
???*/?
??focus:?function(element)?{?
????$(element).focus();?
??},?
??
??/**?
???*?判斷參數引用對象值是否為空,如為空,返回false,?反之true?
???*/?
??present:?function()?{?
????for?(var?i?=?0;?i?<?arguments.length;?i++)?
??????if?($(arguments[i]).value?==?'')?return?false;?
????return?true;?
??},?
??
??/**?
???*?使選中參數引用對象?
???*/?
??select:?function(element)?{?
????$(element).select();?
??},?
??/**?
???*?使參數引用對象處于可編輯狀態?
???*/?
??activate:?function(element)?{?
????$(element).focus();?
????$(element).select();?
??}?
}?
/*--------------------------------------------------------------------------*/?
/**?
?*?表單工具類?
?*/?
var?Form?=?{?
??/**?
???*?將表單元素序列化后的值組合成?QueryString?的形式?
???*/?
??serialize:?function(form)?{?
????var?elements?=?Form.getElements($(form));?
????var?queryComponents?=?new?Array();?
????
????for?(var?i?=?0;?i?<?elements.length;?i++)?{?
??????var?queryComponent?=?Form.Element.serialize(elements[i]);?
??????if?(queryComponent)?
????????queryComponents.push(queryComponent);?
????}?
????
????return?queryComponents.join('&');?
??},?
??
??/**?
???*?得到表單的所有元素對象?
???*/?
??getElements:?function(form)?{?
????form?=?$(form);?
????var?elements?=?new?Array();?
????for?(tagName?in?Form.Element.Serializers)?{?
??????var?tagElements?=?form.getElementsByTagName(tagName);?
??????for?(var?j?=?0;?j?<?tagElements.length;?j++)?
????????elements.push(tagElements[j]);?
????}?
????return?elements;?
??},?
??
??/**?
???*?將指定表單的元素置于不可用狀態?
???*/?
??disable:?function(form)?{?
????var?elements?=?Form.getElements(form);?
????for?(var?i?=?0;?i?<?elements.length;?i++)?{?
??????var?element?=?elements[i];?
??????element.blur();?
??????element.disable?=?'true';?
????}?
??},?
??/**?
???*?使表單的第一個非?hidden?類型而且處于可用狀態的元素獲得焦點?
???*/?
??focusFirstElement:?function(form)?{?
????form?=?$(form);?
????var?elements?=?Form.getElements(form);?
????for?(var?i?=?0;?i?<?elements.length;?i++)?{?
??????var?element?=?elements[i];?
??????if?(element.type?!=?'hidden'?&&?!element.disabled)?{?
????????Field.activate(element);?
????????break;?
??????}?
????}?
??},?
??/*?
???*?重置表單?
???*/?
??reset:?function(form)?{?
????$(form).reset();?
??}?
}?
/**?
?*?表單元素工具類?
?*/?
Form.Element?=?{?
??/**?
???*?返回表單元素的值先序列化再進行?URL?編碼后的值?
???*/?
??serialize:?function(element)?{?
????element?=?$(element);?
????var?method?=?element.tagName.toLowerCase();?
????var?parameter?=?Form.Element.Serializers[method](element);?
????
????if?(parameter)?
??????return?encodeURIComponent(parameter[0])?+?'='?+?
????????encodeURIComponent(parameter[1]);????????????????????
??},?
??
??/**?
???*??返回表單元素序列化后的值?
???*/?
??getValue:?function(element)?{?
????element?=?$(element);?
????var?method?=?element.tagName.toLowerCase();?
????var?parameter?=?Form.Element.Serializers[method](element);?
????
????if?(parameter)?
??????return?parameter[1];?
??}?
}?
/**?
?*?prototype?的所謂序列化其實就是將表單的名字和值組合成一個數組?
?*/?
Form.Element.Serializers?=?{?
??input:?function(element)?{?
????switch?(element.type.toLowerCase())?{?
??????case?'hidden':?
??????case?'password':?
??????case?'text':?
????????return?Form.Element.Serializers.textarea(element);?
??????case?'checkbox':??
??????case?'radio':?
????????return?Form.Element.Serializers.inputSelector(element);?
????}?
????return?false;?
??},?
??
??inputSelector:?function(element)?{?
????if?(element.checked)?
??????return?[element.name,?element.value];?
??},?
??textarea:?function(element)?{?
????return?[element.name,?element.value];?
??},?
??/**?
???*?看樣子,也不支持多選框(select-multiple)?
???*/?
??select:?function(element)?{?
????var?index?=?element.selectedIndex;?
????var?value?=?element.options[index].value?||?element.options[index].text;?
????return?[element.name,?(index?>=?0)???value?:?''];?
??}?
}?
/*--------------------------------------------------------------------------*/?
/**?
?*?Form.Element.getValue?也許會經常用到,所以做了一個快捷引用?
?*/?
var?$F?=?Form.Element.getValue;?
/*--------------------------------------------------------------------------*/?
/**?
?*?Abstract.TimedObserver?也沒有用?Class.create()?來創建,和Ajax.Base?意圖應該一樣?
?*?Abstract.TimedObserver?顧名思義,是套用Observer設計模式來跟蹤指定表單元素,?
?*?當表單元素的值發生變化的時候,就執行回調函數?
?*?
?*?我想 Observer?與注冊onchange事件相似,不同點在于?onchange?事件是在元素失去焦點的時候才激發。?
?*?同樣的與?onpropertychange?事件也相似,不過它只關注表單元素的值的變化,而且提供timeout的控制。?
?*?
?*?除此之外,Observer?的好處大概就在與更面向對象,另外可以動態的更換回調函數,這就比注冊事件要靈活一些。?
?*?Observer?應該可以勝任動態數據校驗,或者多個關聯下拉選項列表的連動等等?
?*?
?*/?
Abstract.TimedObserver?=?function()?{}?
/**?
?*?這個設計和?PeriodicalExecuter?一樣,bind?方法是實現的核心?
?*/?
Abstract.TimedObserver.prototype?=?{?
??initialize:?function(element,?frequency,?callback)?{?
????this.frequency?=?frequency;?
????this.element???=?$(element);?
????this.callback??=?callback;?
????
????this.lastValue?=?this.getValue();?
????this.registerCallback();?
??},?
??
??registerCallback:?function()?{?
????setTimeout(this.onTimerEvent.bind(this),?this.frequency?*?1000);?
??},?
??
??onTimerEvent:?function()?{?
????var?value?=?this.getValue();?
????if?(this.lastValue?!=?value)?{?
??????this.callback(this.element,?value);?
??????this.lastValue?=?value;?
????}?
????
????this.registerCallback();?
??}?
}?
/**?
?*?Form.Element.Observer?和?Form.Observer?其實是一樣的?
?*?注意?Form.Observer?并不是用來跟蹤整個表單的,我想大概只是為了減少書寫(這是Ruby的一個設計原則)?
?*/?
Form.Element.Observer?=?Class.create();?
Form.Element.Observer.prototype?=?(new?Abstract.TimedObserver()).extend({?
??getValue:?function()?{?
????return?Form.Element.getValue(this.element);?
??}?
});?
Form.Observer?=?Class.create();?
Form.Observer.prototype?=?(new?Abstract.TimedObserver()).extend({?
??getValue:?function()?{?
????return?Form.serialize(this.element);?
??}?
});?
?
/**??*?根據?class?attribute?的名字得到對象數組,支持?multiple?class?
?*?
?*/?
document.getElementsByClassName?=?function(className)?{?
??var?children?=?document.getElementsByTagName('*')?||?document.all;?
??var?elements?=?new?Array();?
??
??for?(var?i?=?0;?i?<?children.length;?i++)?{?
????var?child?=?children[i];?
????var?classNames?=?child.className.split('?');?
????for?(var?j?=?0;?j?<?classNames.length;?j++)?{?
??????if?(classNames[j]?==?className)?{?
????????elements.push(child);?
????????break;?
??????}?
????}?
??}?
??
??return?elements;?
}?
/*--------------------------------------------------------------------------*/?
/**?
?*?Element?就象一個?java?的工具類,主要用來?隱藏/顯示/銷除?對象,以及獲取對象的簡單屬性。?
?*?
?*/?
var?Element?=?{?
??toggle:?function()?{?
????for?(var?i?=?0;?i?<?arguments.length;?i++)?{?
??????var?element?=?$(arguments[i]);?
??????element.style.display?=?
????????(element.style.display?==?'none'???''?:?'none');?
????}?
??},?
??hide:?function()?{?
????for?(var?i?=?0;?i?<?arguments.length;?i++)?{?
??????var?element?=?$(arguments[i]);?
??????element.style.display?=?'none';?
????}?
??},?
??show:?function()?{?
????for?(var?i?=?0;?i?<?arguments.length;?i++)?{?
??????var?element?=?$(arguments[i]);?
??????element.style.display?=?'';?
????}?
??},?
??remove:?function(element)?{?
????element?=?$(element);?
????element.parentNode.removeChild(element);?
??},?
????
??getHeight:?function(element)?{?
????element?=?$(element);?
????return?element.offsetHeight;?
??}?
}?
/**?
?*?為?Element.toggle?做了一個符號連接,大概是兼容性的考慮?
?*/?
var?Toggle?=?new?Object();?
Toggle.display?=?Element.toggle;?
/*--------------------------------------------------------------------------*/?
/**?
?*?動態插入內容的實現,MS的Jscript實現中對象有一個?insertAdjacentHTML?方法(http://msdn.microsoft.com/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’t?Repeat?Yourself?(DRY)?原則?
?*?上文中?Abstract.Insertion?算是一個抽象類,定義了名為 initializeRange?的一個抽象方法?
?*?var?Insertion?=?new?Object() 建立一個命名空間?
?*?Insertion.Before|Top|Bottom|After?就象是四個java中的四個靜態內部類,而它們分別繼承于Abstract.Insertion,并實現了initializeRange方法。?
?*/?
var?Insertion?=?new?Object();?
Insertion.Before?=?Class.create();?
Insertion.Before.prototype?=?(new?Abstract.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?=?(new?Abstract.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?=?(new?Abstract.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?=?(new?Abstract.Insertion('afterEnd')).extend({?
??initializeRange:?function()?{?
????this.range.setStartAfter(this.element);?
??},?
??/**?
???*?將內容插入到指定節點的后面,?與指定節點同級?
???*/?
??insertContent:?function()?{?
????this.element.parentNode.insertBefore(this.fragment,?
??????this.element.nextSibling);?
??}?
});?
prototype 還有兩個源碼文件 effects.js compat.js 就不貼出來了。兩者并不常用,effects.js 看example 做花哨的效果還不錯,不過代碼中沒有太多新鮮的東西。
需要指出的就是
compat.js 中 Funcation.prototype.apply 的實現有兩個錯誤(應該是拼寫錯誤), 我分別貼出來,大家比較一下就清楚了。?
if?(!Function.prototype.apply)?{?
//?Based?on?code?from?http://www.youngpup.net/?
Function.prototype.apply?=?function(object,?parameters)?{?
var?parameterStrings?=?new?Array();?
if?(!object)?object?=?window;?
if?(!parameters)?parameters?=?new?Array();?
for?(var?i?=?0;?i?<?parameters.length;?i++)?
parameterStrings[i]?=?'x['?+?i?+?']';?//Error?1?
object.__apply__?=?this;?
var?result?=?eval('obj.__apply__('?+?//Error?2?
parameterStrings[i].join(',?')?+?')');?
object.__apply__?=?null;?
return?result;?
}?
}?
*/?
if?(!Function.prototype.apply)?{?
??Function.prototype.apply?=?function(object,?parameters)?{?
????var?parameterStrings?=?new?Array();?
????if?(!object)?object?=?window;?
????if?(!parameters)?parameters?=?new?Array();?
????for?(var?i?=?0;?i?<?parameters.length;?i++)?
??????parameterStrings[i]?=?'parameters['?+?i?+?']';?
????object.__apply__?=?this;?
????var?result?=?eval('object.__apply__('?+?parameterStrings.join(',?')?+?')');?
????object.__apply__?=?null;?
????return?result;?
??}?
}?
?
//接下來是我模仿著編寫的一個?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);?
???}?
};?
?使用也很簡單, 調用 new Effect.Blink(elementId) 就好了。
通過對 prototype 源碼的研究,我想我對javascript又有了一點新的體會,而最大的體會就是 《Ajax : A New Approach to Web Applications》文章最后作者對設計人員的建議: to forget what we think we know about the limitations of the Web, and begin to imagine a wider, richer range of possibilities.
轉載于:https://www.cnblogs.com/savageworld/archive/2007/05/05/735994.html
總結
以上是生活随笔為你收集整理的【转】一个优秀的Javascript框架--Prototype解说的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 面试算法题6
- 下一篇: 刚回到北京,倒时差中……