|
在討論設(shè)計模式之前,請確認您已經(jīng)有一定的腳本編程基礎(chǔ),如果不甚了解,建議可以先查閱本人很久之前寫的這篇《淺談Javascript面向?qū)ο缶幊獭氛埧聪乱黄恼隆?
講到設(shè)計模式,不得不先重點著墨于“接口設(shè)計”,因為接口設(shè)計在設(shè)計模式中的意義太大了,大于模式本身。直觀起見,先介紹一下接口定義的形式:
復制代碼 代碼如下:
var interface = new Interface("interface",[["getName",1],["getAge",1]]);
可以看出接口函數(shù)必須包含兩個參數(shù),接口方法定義在一個二維數(shù)組中。上例中定義了兩個接口方法:getName,getAge,這兩個方法都帶一個參數(shù),下面我們詳細看一下Interface函數(shù)的實現(xiàn)代碼,從而加深大家對接口的理解。
復制代碼 代碼如下:
function Interface(name,methods){
if(arguments.length !=2){
console.log("參數(shù)必須為二個");
}
this.name = name;
this.methods = [];
if(methods.length<1){
console.log("第二個參數(shù)不能為空數(shù)組");
}
for(var i=0;len=methods.length,i<len;i++){
if(typeof methods[i][0] !== 'string'){
console.log("第一個參數(shù)數(shù)據(jù)類型必須為字符串");
}
if(methods[i][1] && typeof methods[i][1] !== 'number'){
console.log("第二個參數(shù)數(shù)據(jù)類型必須為整數(shù)型");
}
if(methods[i].length == 1){
methods[i][1] = 0;
}
this.methods.push(methods[i]);
}
}
從代碼中不難看出,接口函數(shù)的定義規(guī)則:[1]Interface函數(shù)只能包含兩個參數(shù),第一個參數(shù)為接口名稱,第二個參數(shù)是一個二維數(shù)組[2]第二個參數(shù)不允許為空數(shù)組[3]methods參數(shù)中的第一個參數(shù)必須為字符串類型,用以定義方法名,第二個參數(shù)必須為整數(shù)類型,用以定義方法的參數(shù)個數(shù)[4]當methods中方法的參數(shù)個數(shù)為0時,可以省略不寫。
接下來要建一個類,讓該類繼承前面定義的interface接口,那該怎么做呢,別急,我們需要新增一個方法,見如下代碼:
復制代碼 代碼如下:
var ioldfish = function(name,age){
this.name = name;
this.age = age;
Interface.regImplement(this,interface);
}
ioldfish.prototype.getName = function(){
alert(this.name);
};
ioldfish.prototype.getAge = function(){
alert(this.age);
};
var fishwl = new ioldfish("老魚",27);
fishwl.getName();
Interface.regImplement就是我們要新增的方法,作用就是讓ioldfish類按照接口interface的規(guī)范編碼,否則將會在firebug的控制臺拋出異常。
看看這個方法的具體實現(xiàn)代碼:
復制代碼 代碼如下:
Interface.regImplement = function(object){
if(arguments.length<2){
console.log("接口繼承參數(shù)不能少于二個");
}
for(var i=1;len = arguments.length,i<len;i++){
var interface = arguments[i];
if(interface.constructor !== Interface){
console.log("第三個參數(shù)開始必須為接口實例");
}
for(var j=0;len=interface.methods.length,j<len;j++){
var method = interface.methods[j][0];
if(!object[method] || typeof object[method] !=="function" || object[method].getParameters().length !== interface.methods[j][1]){
console.log(""+method+"方法接口不匹配");
}
}
}
}
解讀這段代碼,你很容易發(fā)現(xiàn):[1]Interface.regImplement繼承接口函數(shù)的參數(shù)至少要有兩個,如果有第三個參數(shù),那么該參數(shù)必須是Interface接口的實例[2]我們?nèi)ケ闅vinterface接口中的方法,再與新增類中的方法一一匹配,如果發(fā)現(xiàn)繼承了該接口規(guī)范的類缺少某方法,就會拋出錯誤提示。[3]接口對于參數(shù)個數(shù)也進行了匹配,如果接口方法中的參數(shù)個數(shù)與新增類中方法的個數(shù)不匹配也會拋出錯誤提示。
為了匹配方法中參數(shù)個數(shù),這里用到一個getParameters()方法,我們基于Function做個擴展,代碼實現(xiàn)如下:
復制代碼 代碼如下:
Function.prototype.getParameters = function(){
var str = this.toString();
var paramStr = str.slice(str.indexOf("(")+1,str.indexOf(")")).replace(//s*/g,'');
try{
return (paramStr.length ==0 ? [] : paramStr.split(","));
}
catch(err){
console.log("非法函數(shù)");
}
}
接下來,你可以把所講的Interface函數(shù),Interface.regImplement函數(shù),還有Function.prototype.getParameters函數(shù)整合到一個interface.js的文件中,調(diào)試一下新建的這個ioldfish類。看看當類中缺少getAge方法時會怎么樣?建議新手,各類情況都模擬一下,加強理解吧!如果你確信已經(jīng)完全理解接口設(shè)計,那就跟著我繼續(xù)往下走。
Javascript設(shè)計模式之單體模式Singleton
單體模式Singleton:這是最基礎(chǔ)的設(shè)計模式,嚴格來說沒什么模式可言,但是卻很容易用也很好用,支付寶很多組件都是通過單體模式設(shè)計的。事實上在《淺談Javascript面向?qū)ο缶幊獭分嘘U述原型繼承的時候就已經(jīng)用到了該模式,這里簡單帶過,重點說一下惰性單體,這對一些不是所有用戶都需要,在特定情景下才會用到的組件有非常好的優(yōu)化作用,他可以讓組件的實例化推遲到用戶觸發(fā)他的時候。
復制代碼 代碼如下:
var ioldfish = {
name:'老魚',
age:27,
getName:function(){
alert(name);
},
getAge:function(){
alert(age);
}
}
上例是一個最簡單的單體模式,把本人的資料都整合到ioldfish這個對象字面量中,形成一個模塊,同時起到了一個命名空間的作用。
復制代碼 代碼如下:
var ioldfish =(function(){
var name = '老魚';
var age = 27;
return{
getName:function(){
alert(name);
},
getAge:function(){
alert(age);
}
}
})();
對第一個單體做簡單的修改,通過閉包讓name,age成為靜態(tài)私有變量,確保實例化的時候在內(nèi)存中始終只有一份,這樣更符合單體模式的定義。
下面重點介紹一下惰性單體,廢話少說,先看看我們該如何來實現(xiàn)惰性單體:
復制代碼 代碼如下:
var ioldfish = (function(){
var uniqueInstance;
var name = '老魚';
var age = 27;
function constructor(){
return{
getName:function(){
alert(name);
},
getAge:function(){
alert(age);
}
}
}
return{
isInstance:function(){
if(uniqueInstance == null){
uniqueInstance = constructor();
}
return uniqueInstance;
}
}
})();
ioldfish.isInstance().getName();
上面的結(jié)構(gòu)公私分明一目了然,私有變量uniqueInstance(標識類是否已經(jīng)實例化)和私有方法constructor,返回一個公有方法isInstance(通過該方法可以調(diào)用私有方法constructor中定義的方法),形如:ioldfish.isInstance().getName();先通過isInstance()方法判斷其是否被實例化,然后通過getName()方法獲取到閉包內(nèi)的私有變量name。該模式的應(yīng)用場景還是很多的,是不是遇見過頁面中需要加載很大的一個日歷控件,但并非所有用戶都用的到呢?是不是…
Javascript設(shè)計模式之工廠模式Factory
工廠模式Factory:先創(chuàng)建一個抽象類,然后基于這個抽象類派生出子類,并在子類中創(chuàng)建工廠方法,從而把實例化推遲到對應(yīng)的子類中進行,說實話,工廠模式在Javascript中的應(yīng)用有些牽強,畢竟Javascript不像Java存在硬編碼帶來的困攪,要學習的只是模式的思想,切忌因為模式而模式。
不妨舉個偏激點的例子,為tab切換、下拉列表等組件添加定位,漸隱,延遲等效果,我們可以先為這些組件定義一個接口:
var Iwidget = new Interface("iwidget",[["addEffect"]]);
定義該接口,以便之后派生的子類繼承,接口中定義了一個addEffect方法,接口方法實現(xiàn)后,調(diào)用的同學大可不必關(guān)注各子類中對于addEffect方法的代碼實現(xiàn)。
復制代碼 代碼如下:
var Widget = function(){};
Widget.prototype={
fire:function(model){
var widget = this.createWidget(model);
//有同學問為什么子類都必須定義接口方法,因為下面要調(diào)用嘛
widget.addEffect();
return widget;
},
show:function(){
//show代碼具體實現(xiàn)
},
hide:function(){
//hide代碼具體實現(xiàn)
},
createWidget:function(model){
alert('抽象類,不可以實例化')
}
};
上例先定義一個抽象類Widget,做為派生子類的父類,由于考慮到這兩類組件都涉及到隱藏和顯示一個容器,所以在父類中預先定義好show和hide方法以便子類繼承。
復制代碼 代碼如下:
var xTab = function(){};
extend(xTab,Widget);
xTab.prototype.createWidget = function(model){
var widget;
switch(model){
case 'position':
widget = new xTabPosition();
break;
case 'anim':
widget = new xTabAnim();
break;
case 'delay':
default:
widget = new xTabDelay();
}
};
var dropDown = function(){};
extend(dropDown,Widget);
dropDown.prototype.createWidget = function(model){
var widget;
switch(model){
case 'position':
widget = new dropDownPosition();
break;
case 'anim':
widget = new dropDownAnim();
break;
case 'delay':
default:
widget = new dropDownDelay();
}
};
子類xTab和dropDown繼承了父類,并且重寫了createWidget方法,不同的子類根據(jù)定位,漸隱,延遲效果分別創(chuàng)建不同的實例,只要創(chuàng)建這些實例的類都實現(xiàn)接口中約定的addEffect方法,至于方法代碼如何實現(xiàn),千篇一律,愛咋整咋整。
復制代碼 代碼如下:
var xTabPosition = function(){};
xTabPosition.prototype ={
addEffect:function(){
//具體實現(xiàn)代碼
}
};
var dropDownPosition = function(){};
dropDownPosition.prototype ={
addEffect:function(){
//具體實現(xiàn)代碼
}
};
var dropDownInstance = new dropDown();
dropDownInstance.fire('position');
以此類推,如果您需要為氣泡組件添加這些效果,照葫蘆畫瓢就可以了,說到這里你可以清楚的看到,這種設(shè)計模式大大降低了類和類之間的耦合度,而且可以根據(jù)具體的交互需求,實現(xiàn)不同的輔助動作,但是也無可避免的增加了代碼實現(xiàn)上的復雜性,事實上這種模式并不適合Javascript,畢竟它有別于Java,不會有類名硬編碼的問題,目的是學習他的設(shè)計思想,所以以上示例僅供參考,如無大人在旁,小朋友切勿效仿。
對于Javascript愛好者來說,更有價值的應(yīng)該是工廠模式中講到的的”緩存(memoization)機制”,書上舉了個創(chuàng)建XHR對象的例子來說明該特性,但是效果顯然不夠明顯……
memoization名詞解釋:把函數(shù)的每次執(zhí)行結(jié)果都放入一個鍵值對(數(shù)組也可以,視情況而定)中,在接下來的執(zhí)行中,在鍵值對中查找是否已經(jīng)有相應(yīng)執(zhí)行過的值,如果有,直接返回該值,沒有才 真正執(zhí)行函數(shù)體的求值部分。很明顯,找值,尤其是在鍵值對中找值,比執(zhí)行函數(shù)快多了
在遞歸調(diào)用的時候,memoization的威力才能更好的顯現(xiàn)。下面是一個經(jīng)典的斐波納契序列,fib(20) 會把fib這個方法執(zhí)行21891次,如果是fib(40),這會執(zhí)行331160281次。
復制代碼 代碼如下:
function fib(n) {
if (n < 2) {
return n;
}
return fib(n - 1) + fib(n - 2);
}
再看看如何使用memoization來實現(xiàn):
復制代碼 代碼如下:
var iterMemoFib = (function() {
var cache = [1, 1];
var fib = function(n) {
if (n >= cache.length) {
//將一個遞歸轉(zhuǎn)換成了一個
for (var i = cache.length; i <= n; i++) {
cache[i] = cache[i - 2] + cache[i - 1];
}
}
return cache[n-1];
}
return fib;
})();
將Function的原型擴展memoize 和unmemoize 方法,這樣你可以對任何函數(shù)實現(xiàn)memoize和解除memoize,當然,這個方法要慎,對一些不是頻繁執(zhí)行的函數(shù),沒必要緩存:
復制代碼 代碼如下:
Function.prototype.memoize = function() {
var pad = {};
var self = this;
var obj = arguments.length > 0 ? arguments[i] : null;
var memoizedFn = function() {
// 把參數(shù)作為數(shù)組保存,作為鍵,把函數(shù)執(zhí)行的結(jié)果作為值緩存起來
var args = [];
for (var i = 0; i < arguments.length; i++) {
args[i] = arguments[i];
}
if (!(args in pad)) {
pad[args] = self.apply(obj, arguments);
}
return pad[args];
}
memoizedFn.unmemoize = function() {
return self;
}
return memoizedFn;
}
Function.prototype.unmemoize = function() {
alert("Attempt to unmemoize an unmemoized function.");
return null;
}
使用方法:fib.memoize();
Javascript設(shè)計模式之組合模式
組合模式:運用該設(shè)計模式可以通過組合對象添加屬性和方法,通過遞歸批量式的讓葉子對象得到組合對象的屬性和方法。打個比方我們現(xiàn)在要動態(tài)創(chuàng)建一個銀行列表,按銀行類型分為網(wǎng)上銀行類,卡通銀行類,并可配置他們是否顯示。用組合模式如何實現(xiàn)呢?
第一步還是先定義接口,因為要做到某類銀行甚至某個銀行是否顯示可配置,那么我們先約定2個接口,showBank和hideBank。
var IcardItem = new Interface(”icardItem”,[["showBank"],["hideBank"]]);
接下來先定義卡的組合對象,并設(shè)置組合對象的基本方法add,remove,getChild,由于這個類繼承了IcardItem接口類,所以還定義了showBank,hideBank這兩個接口方法。
復制代碼 代碼如下:
var cardMain = function(id){
this.cards = [];
this.element = document.createElement("div");
this.element.id = id;
Interface.regImplement(this,IcardItem);
};
cardMain.prototype = {
add:function(card){
this.cards.push(card);
this.element.appendChild(card.getElement());
},
remove:function(card){
for(i=0;len=this.cards.length,i<len;i++){
if(cards[i] == card){
this.cards.splice(i,1);
break;
}
this.element.removeChild(card.getElement());
}
},
getChild:function(i){
return this.cards[i];
},
getElement:function(){
return this.element;
},
showBank:function(){
this.element.style.display ="block";
for(i=0;len=this.cards.length,i<len;i++){
this.cards[i].showBank();
}
},
hideBank:function(){
this.element.style.display ="none";
for(i=0;len=this.cards.length,i<len;i++){
this.cards[i].hideBank();
}
}
};
然后定義葉子對象類bankLogo用以創(chuàng)建銀行l(wèi)ogo,這里銀行l(wèi)ogo都以帶class的a標簽標識:
復制代碼 代碼如下:
var bankLogo = function(bankClassName){
this.element = document.createElement("a");
this.element.className = bankClassName;
Interface.regImplement(this,IcardItem);
};
bankLogo.prototype ={
showBank:function(){
this.element.style.display ="block";
},
hideBank:function(){
this.element.style.display ="none";
},
getElement:function(){
return this.element;
}
};
最后設(shè)置一個單體對象,將操作銀行的相關(guān)信息形成一個模塊,方便調(diào)用:
復制代碼 代碼如下:
var BankAction ={
bankList:[],
addBank:function(card){
this.bankList.push(card);
},
innerBank:function(conId){
for(i=0;len=this.bankList.length,i<len;i++){
var cardObj =this.bankList[i].getElement();
}
document.getElementById(conId).appendChild(cardObj);
}
};
到了實現(xiàn)環(huán)節(jié)了,實例化生成一個包含所有卡的最外層容器,然后根據(jù)卡類,分別生成一個放置銀行卡和卡通卡的容器,最后生成各銀行卡的實例,并按層級關(guān)系形成DOM結(jié)構(gòu):
復制代碼 代碼如下:
var bankDivT = new cardMain("PayCard");//創(chuàng)建最外層容器
var ebankCard = new cardMain("ebankCard");//創(chuàng)建網(wǎng)銀類銀行卡容器
var ktCard = new cardMain("ktCard");//創(chuàng)建卡通類銀行卡容器
var ccbBank = new bankLogo('Ebank-CMB');//創(chuàng)建招行銀行卡
var abcBank = new bankLogo('Ebank-ABC');//創(chuàng)建農(nóng)行銀行卡
var abcKtBank = new bankLogo('Kt-ABC');//創(chuàng)建卡通農(nóng)行卡
ebankCard.add(ccbBank);
ebankCard.add(abcBank);
ktCard.add(abcKtBank);
bankDivT.add(ebankCard);
bankDivT.add(ktCard);
BankAction.addBank(bankDivT);
BankAction.innerBank("bankList");
將動態(tài)生成的銀行列表,DOM結(jié)構(gòu)形如:
復制代碼 代碼如下:
<div id="PayCard">
<div id="ebankCard">
<a class="Ebank-CMB"></a>
<a class="Ebank-ABC"></a>
</div>
<div id="ktCard">
<a class="Kt-ABC"></a>
</div>
</div>
組合模式應(yīng)用在動態(tài)生成用戶界面的時候,是非常不錯的選擇,他可以很大程度的簡化粘合性代碼,提升維護性。不過還是要慎用,畢竟當葉子對象很多的時候,遞歸還是存在性能上的問題。
Javascript設(shè)計模式之裝飾者模式
裝飾者模式:可以不創(chuàng)建新的子類,給對象創(chuàng)建新的功能。舉例說明:支付寶收銀臺紅包結(jié)合余額付款的應(yīng)用場景。
var Ieconomics = new Interface("ieconomics",[["getPrice"]]);
首先創(chuàng)建一個組件類,基與該組件實例化的對象,會被作為參數(shù)傳遞給裝飾者類,以便裝飾者調(diào)用到該組件中的各方法。
復制代碼 代碼如下:
var economic = function(){
Interface.regImplement(this,Ieconomics);
};
economic.prototype={
getPrice:function(){
//代碼實現(xiàn)
}
};
然后創(chuàng)建一個裝飾者抽象類,作為派生裝飾者選件類的父類:
復制代碼 代碼如下:
var economicsDecorator = function(economic){
this.economic = economic;
this.regImplement(economic,Ieconomics);
};
economicsDecorator.prototype={
getPrice:function(){
return this.economic.getPrice();
}
};
最后基于上面這個抽象類,派生出一個裝飾者選件類:
復制代碼 代碼如下:
//紅包裝飾者選件類
var coupon = function(economic){
//調(diào)用裝飾著抽象類的構(gòu)造函數(shù)
economicsDecorator.call(this,economic);
};
extend(coupon,couponDecorator);
coupon.prototype=function(){
//改寫getPrice方法
getPrice:function(){
return this.economic.getPrice() - this.getCoupon();
},
getCoupon:function(){
//獲取紅包總價具體實現(xiàn)
}
};
var myCoupon = new economic();
myCoupon = new coupon(myCoupon);
實現(xiàn)裝飾者模式就是這么簡單,首先創(chuàng)建一個組件的實例myCoupon,然后將該對象作為參數(shù)傳遞給裝飾者選件類coupon。你會發(fā)現(xiàn)兩句代碼中我都把值賦給了變量myCoupon,這是因為他們都實現(xiàn)了同一個接口類,他們之間是可以互換使用的。
看到這里心細的同學可能會發(fā)現(xiàn),我們在coupon類中新增了一個getCoupon方法,目前來看不會有任何問題,但是如果我們繼續(xù)創(chuàng)建一個購物卷裝飾者選件類,然后結(jié)合紅包一起用呢?
復制代碼 代碼如下:
//購物卷裝飾者選件類
var voucher = function(economic){
economicsDecorator.call(this,economic);
};
extend(voucher,couponDecorator);
voucher.prototype=function(){
getPrice:function(){
return this.getPrice() - this.getVoucher();
},
getVoucher:function(){
//獲取優(yōu)惠卷總價具體實現(xiàn)
}
};
var myCoupon = new economic();
myCoupon = new coupon(myCoupon);
myCoupon = new voucher(myCoupon);
在這種場景下面getCoupon方法已經(jīng)找不到了,這是因為voucher裝飾myCoupon的時候,它的父類economicsDecorator不包含getCoupon方法,那自然是取不到的了,那該怎么辦呢?
分析一下裝飾者抽象類economicsDecorator,我們傳遞了一個myCoupon的引用作為參數(shù),我們可以通過這個參數(shù)做一些小動作,獲得新增加的方法。
復制代碼 代碼如下:
var economicsDecorator = function(economic){
this.economic = economic;
this.interface = Ieconomics;
for(var k in this.economic){
if(typeof this.economic[key] !== "function"){
continue;
var i;
for(i = 0;len = this.interface.methods.length,i < len; i++) {
//通過遍歷比較在接口類中是否包含此方法,如果包含返回下一個
if(key == this.interface.methods[i][0]) {
break;
}
}
if(i < this.interface.methods.length)
continue;
var decorator = this;
//采用匿名函數(shù)調(diào)用方式來定義新方法
(function(methodName) {
decorator[methodName] = function() {
return decorator.economic[methodName]();
};
})(key);
}
}
}
this.regImplement(economic,Ieconomics);
};
economicsDecorator.prototype={
getPrice:function(){
return this.economic.getPrice();
}
};
看上面的代碼,我們對裝飾者抽象類做了一些修改,這樣做是為了確保在裝飾者選件類中一旦定義新方法,可以在裝飾者抽象類中動態(tài)的定義出來。這里只是提供一個使用裝飾者模式的思路,具體的實現(xiàn)代碼遠比這個復雜,由于項目還在開發(fā)中,demo暫不提供,支付寶新版收銀臺發(fā)布后,會跟大家再做個詳細的設(shè)計分享。
Javascript設(shè)計模式之橋接模式
橋接模式:將抽象和其實現(xiàn)分離開來,以便二者獨立變化。其實很簡單,只是在API和具體事件之間增加一個橋梁,從而降低API和使用他的類和對象之間的耦合。
事實上對大多數(shù)同學來說橋接模式并不陌生,下面的this.getName就是一種橋接方法,他是外訪問的一個接口,他的內(nèi)部實現(xiàn)是通過訪問內(nèi)部私有變量來實現(xiàn)的,這個方法起到了外部和內(nèi)部溝通的橋梁作用。
復制代碼 代碼如下:
var ioldfish = function(){
var name = '老魚';
this.getName = function(){
alert(name);
}
}
橋接模式用的最多的還是在事件監(jiān)聽器回調(diào)函數(shù)。下面這個是獲取用戶信息的API接口函數(shù):
復制代碼 代碼如下:
function getUserInfo(userid,callback){
asyncRequest('GET','userInfo?userid='+userid,function(resp){
callback(resp.responseText);
});
}
接下去我們要做的是把這個API和某個事件的觸發(fā)建立一個橋梁關(guān)系
addEvent(element,'click',bridgeMethod);
function bridgeMethod(e){
getUserInfo(this.userid,function(){
//回調(diào)函數(shù)實現(xiàn)代碼
});
}
這里在element對象click的時候觸發(fā)函數(shù)并不是getIserInfo,而是新建了一個橋接方法bridgeMethod,通過這層橋接使得API接口函數(shù)和click事件相對獨立,這樣大大拓寬了API的適用范圍。
Javascript設(shè)計模式之適配器模式
適配器模式:打個比方,你維護了一個系統(tǒng),之前一直都是用prototype框架,但是現(xiàn)在打算新引入YUI框架,那如何讓兩個框架平穩(wěn)過度呢
,舉個例子,如何將prototype中的$方法轉(zhuǎn)換為YUI中的get方法:
復制代碼 代碼如下:
function $(){};
function YAHOO.util.Dom.get=function(el){};
function prototypeToYuiAdapter(){
return YAHOO.util.Dom.get(arguments);
}
你要在prototype中使用yui的get方法,只需要做以下申明即可:
$ = prototypeToYuiAdapter;
這樣的話,在prototype中就可以使用YUI中的get方法了。本人并不是很推崇這種模式,所以不多做闡述,事實上我覺得不到萬不得以,我們根本不需要使用這種模式,作為一名負責任的設(shè)計者,我寧可做代碼重構(gòu)也不希望使用該模式,只能作為無奈之下的過渡型方案使用。
Javascript設(shè)計模式之門面模式,觀察者模式
門面模式:這應(yīng)該是所有腳本框架中都用到的,最基礎(chǔ)的設(shè)計模式,隨便找個框架中定義好的方法看看就行了,比如說YUI中的setStyle方法等等等等。在這里就不多闡述了。
觀察者模式:該設(shè)計模式應(yīng)用在Javascript上似乎更為牽強,不甚理解,這里就不說了,以免誤人子第,如有心得者不吝賜教。
一天時間都耗在這篇博文上了,好象還有很多想寫的,看來要把心里想的東西寫清楚還是不容易的,再整理整理再說吧,敬請期待!
JavaScript技術(shù):小議javascript 設(shè)計模式 推薦,轉(zhuǎn)載需保留來源!
鄭重聲明:本文版權(quán)歸原作者所有,轉(zhuǎn)載文章僅為傳播更多信息之目的,如作者信息標記有誤,請第一時間聯(lián)系我們修改或刪除,多謝。