Javascript自定义事件,其本质就是观察者模式(又称订阅/发布模式),它的好处就是将绑定事件和触发事件相互隔离开,并且可以动态的添加、删除事件。

下面通过实例,一步一步构建一个具体的Javascript自定义事件对象。

如:我有一个action1函数,我想每次在执行完action1后,触发另一个函数service1,那么代码我们可以这么写:

//服务service1
function service1(){ }
//函数action
function 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:用于删除一个指定的service
function del(arr, fn){
for(var i = 0; i < arr.length; i++){
if( arr[i] == fn ){
arr.splice(i,1);
break;
}
}
}
//action1后,执行所有的service
function action1(){
//other things
//遍历serviceaary,执行所有service函数。(servicearray在action1内)
for(var i =0; i < servicearray.length; i++){
servicearray[i]();
}
}
//添加service4
function service4(){}
servicearray.push(service4);
//删除service2
del(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;
}
}
}
//添加一个service4
function service4(){}
servicearray.push(service4);
//删除一个service2
del(servicearray, service2);
//添加一个触发函数hanldeAction,分离action与service
function 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;
}
}
}
//添加一个service4
function service4(){}
servicearray.push(service4);
//删除一个service2
del(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之自定义事件的更多相关文章

  1. 详解javascript实现自定义事件

    这篇文章主要为大家介绍了javascript实现自定义事件的方法,自定义事件,顾名思义,就是自己定义事件类型,自己定义事件处理函数,javascript如何实现自定义事件,需要了解的朋友可以参考下 我 ...

  2. JavaScript使用自定义事件实现简单的模块化开发

    WEB前端最常见驱动方式就是事件了, 所有交互等等都是通过事件,前端的常见事件有: UI事件: 焦点事件: 鼠标事件: 滚轮事件: 文本事件: 键盘事件: 变动事件: 现在网页上有一个输入框, 如果我 ...

  3. javascript中自定义事件

    自定义事件:用户可以指定事件类型,这个类型实际上就是一个字符串,然后为这个类型的事件指定事件处理函数,可以注册多个事件处理函数(用数组管理),调用时,从多个事件处理函数中找到再调用. function ...

  4. 使用jQuery在javascript中自定义事件

    js中的自定义事件有attachEvent,addEventListener等等好多种,往往受困于浏览器兼容,而且代码写起来也相当麻烦.jQuery为我们解决了这个问题,几行代码就可以很好的实现事件的 ...

  5. 利用javascript(自定义事件)记录尺寸可变元素的尺寸变化过程

    1.效果图 2.源码 <%@ page contentType="text/html;charset=UTF-8" language="java" %&g ...

  6. javascript和jquey的自定义事件小结

    “通过事件机制,可以将类设计为独立的模块,通过事件对外通信,提高了程序的开发效率.” 可以把多个关联但逻辑复杂的操作利用自定义事件的机制灵活地控制好 对象之间通过直接方法调用来交互 1)对象A直接调用 ...

  7. javascript事件之:谈谈自定义事件(转)

    http://www.cnblogs.com/pfzeng/p/4162951.html 对于JavaScript自定义事件,印象最深刻的是用jQuery在做图片懒加载的时候.给需要懒加载的图片定义一 ...

  8. Javascript事件模型系列(四)我所理解的javascript自定义事件

    被我拖延了将近一个月的javascript事件模型系列终于迎来了第四篇,也是我计划中的最后一篇,说来太惭愧了,本来计划一到两个星期写完的,谁知中间遇到了很多事情,公司的个人的,搞的自己心烦意乱浮躁了一 ...

  9. javascript事件之:谈谈自定义事件

    对于JavaScript自定义事件,印象最深刻的是用jQuery在做图片懒加载的时候.给需要懒加载的图片定义一个appear事件.当页面图片开始出现时候,触发这个自定义的appear事件(注意,这里只 ...

随机推荐

  1. 【AR实验室】ARToolKit之制作自己的Marker/NFT

    0x00 - 前言 看过example后,就会想自己动动手,这里改改那里修修.我们先试着添加自己喜欢的marker/nft进行识别. 比如我做了一个法拉利的marker: 还有网上找了一个法拉利log ...

  2. rnandroid环境搭建

    react-native 环境搭建具体步骤这个大家已经玩烂了,这个主要是记录下来自己做win7系统遇到的坑 1.com.android.ddmlib.installexception 遇到这个问题,在 ...

  3. javascript中的继承与深度拷贝

    前言 本篇适合前端新人,下面开始...... 对于前端新手来说(比如博主),每当对js的对象做操作时,都是一种痛苦,原因就是在于对象的赋值是引用的传递,并非值的传递,虽然看上去后者赋值给了前者,他们就 ...

  4. C#创建dll类库

    类库让我们的代码可复用,我们只需要在类库中声明变量一次,就能在接下来的过程中无数次地使用,而无需在每次使用前都要声明它.这样一来,就节省了我们的内存空间.而想要在类库添加什么类,还需取决于类库要实现哪 ...

  5. [原] KVM 虚拟化原理探究(3)— CPU 虚拟化

    KVM 虚拟化原理探究(3)- CPU 虚拟化 标签(空格分隔): KVM [TOC] CPU 虚拟化简介 上一篇文章笼统的介绍了一个虚拟机的诞生过程,从demo中也可以看到,运行一个虚拟机再也不需要 ...

  6. 代码的坏味道(22)——不完美的库类(Incomplete Library Class)

    坏味道--不完美的库类(Incomplete Library Class) 特征 当一个类库已经不能满足实际需要时,你就不得不改变这个库(如果这个库是只读的,那就没辙了). 问题原因 许多编程技术都建 ...

  7. 如何使用swing创建一个BeatBox

    首先,我们需要回顾一些内容(2017-01-04 14:32:14): 1.Swing组件 Swing的组件(component,或者称之为元件),是较widget更为正确的术语,它们就是会放在GUI ...

  8. 【Java每日一题】20170104

    20170103问题解析请点击今日问题下方的"[Java每日一题]20170104"查看(问题解析在公众号首发,公众号ID:weknow619) package Jan2017; ...

  9. Unicode 和 UTF-8 有何区别?

    Unicode符号范围 (一个字符两个字节)     | UTF-8编码方式 (十六进制)     | (二进制) —————————————————————– 这儿有四个字节从-----00 00 ...

  10. hbase集群安装与部署

    1.相关环境 centos7 hadoop2.6.5 zookeeper3.4.9 jdk1.8 hbase1.2.4 本篇文章仅涉及hbase集群的搭建,关于hadoop与zookeeper的相关部 ...