百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 编程字典 > 正文

自己实现一个javascript事件模块

toyiye 2024-06-21 12:06 11 浏览 0 评论

nodejs中的事件模块

nodejs中有一个events模块,用来给别的函数对象提供绑定事件、触发事件的能力。这个别的函数的对象,我把它叫做事件宿主对象(非权威叫法),其原理是把宿主函数的原型链指向时间模块的一个对象,做一个函数继承,让宿主函数也拥有处理事件的能力 使用nodejs事件模块的demo如下:

var EventEmitter = require('events');
var util = require('util');

function MyEmitter {
    EventEmitter.call(this);
}
util.inherits(MyEmitter, EventEmitter);

var myEmitter = new MyEmitter;
myEmitter.on("hehe",function{
    console.log("hehe")
})
myEmitter.on("hehe",function{
    console.log("haha")
})
myEmitter.emit("hehe");
console.log(myEmitter.listeners("hehe"));

看node events的api http://nodejs.cn/api/events.html,一个事件模块需要具备如下的基本功能:

  • 添加绑定事件
  • 添加绑定一次性事件
  • 移除事件监听
  • 触发事件
  • 其他需要的扩展

事件模块设计

自己实现一个简单的事件系统,实现上面几个基本的功能就行。

捋一捋思路,我们需要先实现一个事件类,用来创建不同名称的事件对象,例如click事件对象,hehe事件对象等,并在对象内部维持一个事件被触发时的处理函数列表。

对于同一个事件宿主对象而言,对它绑定的事件应该有如下特点:

  1. 同一种类型的事件对象只需要有一个
  2. 处理函数需要有多个
  3. 对于同一个事件,重复绑定同一个事件处理函数应该是无效的

于是得到如下结构:

/**
 * 定义一个事件单元类
 * @param eventname
 * @constructor
 */
function EventMeta(eventname){
    this.name=eventname;
    this.handlerMap={};
    this.handlerList=;
}

每个事件宿主对象都应该自己持有一个map,用来保存自己的事件单元对象,加上上面所说的,绑定,一次性绑定、解绑、触发,宿主函数的原型应该被指向这样一个对象:

 var prototype={
        addEventListener:addEventListener,
        once:once,
        removeEventListener:removeEventListener,
        trigger:trigger,
        getEventHandlerMap:getEventHandlerMap
  }

为了让宿主函数拥有这些属性,需要一个函数来为宿主函数指一下prototype属性,这里要注意的是,一定要调用这个函数之后,再扩展宿主函数自身的prototype属性,否则会被覆盖

function czEvent(fn){
        if(typeof fn!=="function") return;
        fn.prototype=Object.create(prototype);
    }

用户使用的时候这样调用一下就可以了

var czEvent=require("../czEvent");
function MyEmitter {
}
czEvent(MyEmitter);

依次实现事件函数

addEventListener

    /**
     * 绑定事件监听
     * @param type
     * @param handler
     */
    function addEventListener(eventname,handler){
        var EventHandlerMap=this.getEventHandlerMap;
        var meta=EventHandlerMap[eventname];
        if(!meta){
 meta=EventHandlerMap[eventname]=new EventMeta(eventname);
        }
        var handlerId=handler.__handlerId;
        if(!handlerId){
 EventHandlerMap.__handlerId++;
 handler.__handlerId=EventHandlerMap.__handlerId;
 handlerId=handler.__handlerId;
        }
        //对于同一事件的同一处理函数,不重复绑定
        if(!meta.handlerMap[handlerId]){
 meta.handlerMap[handlerId]=handler;
 meta.handlerList.push(handler);
        }
    }

once

    /**
     * 绑定只执行一次的handler
     * @param type
     * @param handler
     */
    function once(eventname,handler){
        handler.__once=true;
        this.addEventListener(eventname,handler);
    }

removeEventListener

    /**
     * 移除事件监听
     * @param type
     * @param handdler
     */
    function removeEventListener(eventname,handdler){
        var EventHandlerMap=this.getEventHandlerMap;
        var meta=EventHandlerMap[eventname];
        if(!meta) return;
        //移除一个handler的绑定
        if(handdler && handdler.__handlerId){
 var index=meta.handlerList.indexOf(handdler);
 if(index>-1){
 meta.handlerList.splice(index,1);
 delete meta.handlerMap[handdler.__handlerId];
 return;
 }
        }
        //移除所有handler
        meta.handlerMap={};
        meta.handlerList.length=0;
    }

trigger

    /**
     * 触发事件
     * @param eventname
     */
    function trigger{
        var EventHandlerMap=this.getEventHandlerMap;
        var args=;
        var that=this;
        for(var i=0;i<arguments.length;i++){
 args.push(arguments[i]);
        }
        var eventname=args.splice(0,1);
        var meta=EventHandlerMap[eventname];
        if(!meta) return;
        var onceHandlerList=;
        //依次同步执行handler
        meta.handlerList.forEach(function(handler){
 if(handler.__once){
 onceHandlerList.push(handler)
 }
 handler.apply(this,args);
        });
        //清除绑定为once的事件
        onceHandlerList.forEach(function(handler){
 that.removeEventListener(eventname,handler);
        });
    }

getEventHandlerMap

    function getEventHandlerMap{
        var EventHandlerMap=this.__EventHandlerMap;
        if(EventHandlerMap) return EventHandlerMap;
        return this.__EventHandlerMap={__handlerId:0};
    }

包装

学(chao)习(xi)一下jquery的包装技术,让模块支持commonJs和amd

/**
 * Created by czzou on 2016/6/30.
 */
( function( global, factory ) {
    "use strict";
    if ( typeof module === "object" && typeof module.exports === "object" ) {
        module.exports = factory( global, true );
    } else {
        factory( global );
    }
}(typeof window !== "undefined" ? window : this,function(window,noGlobal){
    //把上面的代码copy进来
    if ( typeof define === "function" && define.amd ) {
        define( "czEvent", , function {
 return czEvent;
        } );
    }
    if ( !noGlobal ) {
        window.czEvent = czEvent;
    }
    return czEvent;
}))

扩展

如有需求,还可以在此基础上进行一些扩展,比如nodejs的events模块支持的handler函数个数上限、handler函数抛出异常时触发的error事件等,另外,简单改写一下czEvent函数,还可以让事件模块支持给对象赋予事件处理能力的功能

    function czEvent(fn,asObj){
        if(asObj){
 for(var key in prototype){
 Object.defineProperty(fn,key,{
 value:prototype[key]
 })
 }
 return;
        }
        if(typeof fn!=="function") return;
        fn.prototype=Object.create(prototype);
    }

测试

分别测试nodejs的events模块,czEvent的commonJs用法,amd用法以及直接引用用法,demo就不在这里一一列举了~

相关推荐

为何越来越多的编程语言使用JSON(为什么编程)

JSON是JavascriptObjectNotation的缩写,意思是Javascript对象表示法,是一种易于人类阅读和对编程友好的文本数据传递方法,是JavaScript语言规范定义的一个子...

何时在数据库中使用 JSON(数据库用json格式存储)

在本文中,您将了解何时应考虑将JSON数据类型添加到表中以及何时应避免使用它们。每天?分享?最新?软件?开发?,Devops,敏捷?,测试?以及?项目?管理?最新?,最热门?的?文章?,每天?花?...

MySQL 从零开始:05 数据类型(mysql数据类型有哪些,并举例)

前面的讲解中已经接触到了表的创建,表的创建是对字段的声明,比如:上述语句声明了字段的名称、类型、所占空间、默认值和是否可以为空等信息。其中的int、varchar、char和decimal都...

JSON对象花样进阶(json格式对象)

一、引言在现代Web开发中,JSON(JavaScriptObjectNotation)已经成为数据交换的标准格式。无论是从前端向后端发送数据,还是从后端接收数据,JSON都是不可或缺的一部分。...

深入理解 JSON 和 Form-data(json和formdata提交区别)

在讨论现代网络开发与API设计的语境下,理解客户端和服务器间如何有效且可靠地交换数据变得尤为关键。这里,特别值得关注的是两种主流数据格式:...

JSON 语法(json 语法 priority)

JSON语法是JavaScript语法的子集。JSON语法规则JSON语法是JavaScript对象表示法语法的子集。数据在名称/值对中数据由逗号分隔花括号保存对象方括号保存数组JS...

JSON语法详解(json的语法规则)

JSON语法规则JSON语法是JavaScript对象表示法语法的子集。数据在名称/值对中数据由逗号分隔大括号保存对象中括号保存数组注意:json的key是字符串,且必须是双引号,不能是单引号...

MySQL JSON数据类型操作(mysql的json)

概述mysql自5.7.8版本开始,就支持了json结构的数据存储和查询,这表明了mysql也在不断的学习和增加nosql数据库的有点。但mysql毕竟是关系型数据库,在处理json这种非结构化的数据...

JSON的数据模式(json数据格式示例)

像XML模式一样,JSON数据格式也有Schema,这是一个基于JSON格式的规范。JSON模式也以JSON格式编写。它用于验证JSON数据。JSON模式示例以下代码显示了基本的JSON模式。{"...

前端学习——JSON格式详解(后端json格式)

JSON(JavaScriptObjectNotation)是一种轻量级的数据交换格式。易于人阅读和编写。同时也易于机器解析和生成。它基于JavaScriptProgrammingLa...

什么是 JSON:详解 JSON 及其优势(什么叫json)

现在程序员还有谁不知道JSON吗?无论对于前端还是后端,JSON都是一种常见的数据格式。那么JSON到底是什么呢?JSON的定义...

PostgreSQL JSON 类型:处理结构化数据

PostgreSQL提供JSON类型,以存储结构化数据。JSON是一种开放的数据格式,可用于存储各种类型的值。什么是JSON类型?JSON类型表示JSON(JavaScriptO...

JavaScript:JSON、三种包装类(javascript 包)

JOSN:我们希望可以将一个对象在不同的语言中进行传递,以达到通信的目的,最佳方式就是将一个对象转换为字符串的形式JSON(JavaScriptObjectNotation)-JS的对象表示法...

Python数据分析 只要1分钟 教你玩转JSON 全程干货

Json简介:Json,全名JavaScriptObjectNotation,JSON(JavaScriptObjectNotation(记号、标记))是一种轻量级的数据交换格式。它基于J...

比较一下JSON与XML两种数据格式?(json和xml哪个好)

JSON(JavaScriptObjectNotation)和XML(eXtensibleMarkupLanguage)是在日常开发中比较常用的两种数据格式,它们主要的作用就是用来进行数据的传...

取消回复欢迎 发表评论:

请填写验证码