Emitter 对象事件库源码浅析

Emitter 对象事件库

github Emitter

接口

  • on/addEventListener
  • once
  • off/removeListener/removeAllListeners/removeEventListener
  • emit
  • listeners
  • hasListeners

继承方式

  • 继承接口使用方式
    function Job(){
      EventEmitter.call(this);
      // custom initialization here
    }
    Job.prototype = new EventEmitter;
  • 该库使用的方式(可以依照具体情况选择方式进行添加)
    //As an Emitter instance:
    var Emitter = require('emitter');
    var emitter = new Emitter;
    emitter.emit('something');

    //As a mixin:
    var Emitter = require('emitter');
    var user = { name: 'tobi' };
    Emitter(user);
    user.emit('im a user');
    
    //As a prototype mixin:
    var Emitter = require('emitter');
    Emitter(User.prototype);
  • 实现: 通过mixin混合函数将事件函数绑定到对象上
    function mixin(obj) {
  for (var key in Emitter.prototype) {
    obj[key] = Emitter.prototype[key];
  }
  return obj;
  • 接口实现细节
  • once一次调用:回调函数进行封装,调用该函数前调用off进行移除事件
    Emitter.prototype.once = function(event, fn){
      var self = this;
      this._callbacks = this._callbacks || {};
    
      function on() {
        self.off(event, on);
        fn.apply(this, arguments); //防止回调函数的this变成window
      }
    
      on.fn = fn; //这个是为了移除使用,不需要给on保留能索引到的变量,在remove的时候,判断cb.fn是不是跟移除的函数是一致的
      this.on(event, on);
      return this;
    };
  • off 移除事件函数
    *
    Emitter.prototype.removeEventListener = function(event, fn){
      this._callbacks = this._callbacks || {};
      // all
      if (0 == arguments.length) {
        this._callbacks = {};
        return this;
      }
      // specific event
      var callbacks = this._callbacks[event];
      if (!callbacks) return this;
      // remove all handlers
      if (1 == arguments.length) {
        delete this._callbacks[event];
        return this;
      }
      // remove specific handler
      var cb;
      for (var i = 0; i < callbacks.length; i++) {
        cb = callbacks[i];
        if (cb === fn || cb.fn === fn) { //cb.fn === fn是用于once一次调用保留的回调函数
          callbacks.splice(i, 1);
          break;
        }
      }
      return this;
    };
* 代码不如seajs的好理解
      seajs.off = function (name, callback) {
            // Remove *all* events
            if (!(name || callback)) {
                events = data.events = {}
                return seajs
            }
            var list = events[name]
            if (list) {
                if (callback) {
                    for (var i = list.length - 1; i >= 0; i--) {
                        if (list[i] === callback) {
                            list.splice(i, 1)
                        }
                    }
                }
                else {
                    delete events[name]
                }
            }
            return seajs
        }    
  • emit 触发函数:
    *
    Emitter.prototype.emit = function(event){
      this._callbacks = this._callbacks || {};
      var args = [].slice.call(arguments, 1)
        , callbacks = this._callbacks[event];
      if (callbacks) {
        callbacks = callbacks.slice(0);
        for (var i = 0, len = callbacks.length; i < len; ++i) {
          callbacks[i].apply(this, args);
        }
      }
      return this;
    };
* 似乎没有必要添加callbacks = callbacks.slice();  处理函数并不会改变callbacks数组,但有一种实现就需要这样子做:
        while ((fn = list.shift())) {
            fn.apply(this, args);
        }

posted on 2014-12-08 17:20  overview  阅读(375)  评论(0)    收藏  举报

导航