Javascript之自訂事件

來源:互聯網
上載者:User

標籤:

Javascript自訂事件,其本質就是觀察者模式(又稱訂閱/發布模式),它的好處就是將綁定事件和觸發事件相互隔離開,並且可以動態添加、刪除事件。

下面通過執行個體,一步一步構建一個具體的Javascript自訂事件對象。

如:我有一個action1函數,我想每次在執行完action1後,觸發另一個函數service1,那麼代碼我們可以這麼寫:

//服務service1function service1(){}//函數action1function action1(){    //other things    //then 啟動service1    service1();}

Good,但是現在想法變了,我想在action1完成後,不僅觸發service1,還要觸發service2和service3。

按照剛才的思路,在函數action1完成後,順帶加上它們就是了。

如下:

function service1(){}function service2(){}function service3(){}function action1(){    //other things     service1();    service2();    service3();}

但,想法又再次發生波動,在執行完action1函數後,我突然想動態添加一個service4,且,發現service2似乎毫無意義,我不想觸發了,怎麼辦呢?

你可能會說去掉service2,然後在action1後面加入service4不就完了嗎?

但是,在真正的項目開發代碼日益劇增的情況下,談何容易,還要去找到相關代碼進行操作。

那怎麼辦呢?

初步想法,定義一個數組嘛(如:servicearray),用來管理所有的service。

當action1執行到末尾後,遍曆一遍這個數組函數(servicearray),就歐克了嘛。

且,倘若我們不想運行service2了,便將它從這個數組中刪除就好了;倘若想再添加一個新的service,將其追加到servicearray數組中就好了。

如此nice,如下:

var servicearray = [];function service1(){}function service2(){}function service3(){}//將所有service添加到servicearray中servicearray.push(service1);servicearray.push(service2);servicearray.push(service3);//del:用於刪除一個指定的servicefunction del(arr, fn){    for(var i = 0; i < arr.length; i++){        if( arr[i] == fn ){            arr.splice(i,1);            break;        }    } }//action1後,執行所有的servicefunction action1(){    //other things     //遍曆serviceaary,執行所有service函數。(servicearray在action1內)    for(var i =0; i < servicearray.length; i++){        servicearray[i]();    }}//添加service4function service4(){}servicearray.push(service4);//刪除service2del(servicearray, service2);

上面代碼挺歐克的,但,複用性一點都不強,且servicearray與action你中有我,我中有你,不好。我們再來最佳化最佳化。

代碼如下:

var servicearray = [];function service1(){}function service2(){}function service3(){}servicearray.push(service1);servicearray.push(service2);servicearray.push(service3);function del(arr, fn){    for(var i = 0; i < arr.length; i++){        if( arr[i] == fn ){            arr.splice(i,1);            break;        }    } }//添加一個service4function service4(){}servicearray.push(service4);//刪除一個service2del(servicearray, service2);//添加一個觸發函數hanldeAction,分離action與servicefunction hanldeAction(actionName,serviceArr){    if(typeof actionName === ‘function‘){        actionName();        for(var i =0; i < serviceArr.length; i++){            serviceArr[i]();        }    }}//執行handleAction(action1,servicearray); 

上面的代碼和回呼函數有異曲同工之處,因為我們想達到的效果是在 action執行完成之後,運行一系列service嘛。

但,我現在改變想法了,我想在action執行之前執行一系列service呢,或者action中呢。看來得改hanldeAction回呼函數啊,這放在項目中反覆修改,顯然不行。

所以,我們得讓其更強大才好。(我想讓它在什麼地方執行就執行)

如下:

function service1(){}function service2(){}function service3(){}var servicearray = [];servicearray.push(service1);servicearray.push(service2);servicearray.push(service3);function del(arr, fn){    for(var i = 0; i < arr.length; i++){        if( arr[i] == fn ){            arr.splice(i,1);            break;        }    } }//添加一個service4function service4(){}servicearray.push(service4);//刪除一個service2del(servicearray, service2);/*    actionObj用於儲存所有action與service關聯的對象。    如:{            action1:[service1,service2],            action2:[...]        }*/var actionObj = {};/*    修改代碼,增加一個actionName與serviceArr關聯事件。    如,action1關聯所有service,這樣再結合下方的trigger事件就完美了    Params:           actionName --> actionObj的屬性           serviceArr --> 包含所有與actionName相關的service數組*/function addAction(actionName, serviceArr){    if(typeof actionObj[actionName] === ‘undefined‘ ){        actionObj[actionName] = [];    }    if(typeof serviceArr === ‘object‘){        actionObj[actionName].push(serviceArr);    }}/*    修改代碼,增加一個觸發actionName事件    如,當我想觸發action1中的所有service時,調用trigger(action1)就OK啦*/function trigger( actionName ){    var act = actionObj[actionName];    if(act instanceof Array){        for(var i = 0, len = act.length; i < len; i++){            for(var j =0, arrlen = act[i].length; j++){                ((act[i])[j])();            }        }    }}

上述代碼是可以,但,有個效能問題,addAction中添加到actionObj[actionName]中的是一個數組,其實完全可以將定義的servicearray數組(為了儲存不同的service而聲明的數組)移除,轉而將每個service直接push進actionObj[actionName]聲明的數組中,這樣trigger事件效率也得到了提高,從原來的兩層for迴圈降到一層for迴圈。且,我們再加一個刪除service的方法remove。

整理代碼如下:

var actionObj = {};//修改代碼,增加一個actionName與service函數直接關聯事件function addAction(actionName, fn){    if(typeof actionObj[actionName] === ‘undefined‘ ){        actionObj[actionName] = [];    }    if(typeof fn === ‘function‘){        actionObj[actionName].push(fn);    }}//修改代碼,增加一個觸發actionName事件function trigger( actionName ){    var actionarray = actionObj[actionName];    if(actionarray instanceof Array){        for(var i = 0, len = actionarray.length; i < len; i++){            if(typeof actionarray[i] === ‘function‘){                actionarray[i]();            }        }    }}//修改代碼,增加一個刪除actionName中的service事件function remove(actionName, fn){    var actionarray = actionObj[actionName];    if(typeof actionName === ‘string‘ && actionarray instanceof Array){        if(typeof fn === ‘function‘){            //清除actionName中對應的fn方法            for(var i=0, len = actionarray.length; i < len; i++){                if(actionarray[i] === fn){                    actionObj[actionName].splice(i,1);                }            }        }    }}

上面的代碼好是好,action與service也互不影響,也完成了它的使命。

使命?

這就是我們一起編寫的自訂事件嘛。是不是很簡單。

哈哈哈,我尼瑪也在代碼中用到設計模式了(觀察者模式)。

一鼓作氣,我們再來最佳化下上面的代碼。有沒有注意,我們是使用的全域變數,在模組化開發的大環境下,我們居然在用全域變數,豈不是汙染命名空間嘛。再改改。

修改代碼如下:

var EventTarget = function(){    this.listener = {};}EventTarget.prototype = {    constructor:EventTarget,    addAction: function(actionName, fn){        if(typeof actionName === ‘string‘ && typeof fn === ‘function‘){            //如果不存在actionName,就建立一個            if(typeof this.listener[actionName] === ‘undefined‘){                this.listener[actionName] = [fn];            }            //否則,直接往相應actinoName裡面塞            else{                this.listener[actionName].push(fn);            }        }    },    trigger: function(actionName){        var actionArray = this.listener[actionName];        //觸發一系列actionName裡的函數        if(actionArray instanceof Array){            for(var i = 0, len = actionArray.length; i < len; i++){                if(typeof actionArray[i] === ‘function‘){                    actionArray[i]();                }            }           }        actionArray = null;    },    remove: function(actionName, fn){        var actionArray = this.listener[actionName];        if(typeof actionName === ‘string‘ && actionArray instanceof Array){            if(typeof fn === ‘function‘){                //清除actionName中對應的fn方法                for(var i=0, len = actionArray.length; i < len; i++){                    if(actionArray[i] === fn){                        this.listener[actionName].splice(i,1);                    }                }            }        }        actionArray = null;    }};

一個JavaScript自訂事件新鮮出爐。

好了,晚安everyone~

 

Javascript之自訂事件

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.