javascript – 基于回调和基于事件的事件处理系统有什么区别?

我正在开发一个跨浏览器的事件处理系统.我请一些开发人员查看我的代码.其中一位开发人员说我的实现是基于回调而不是真实事件.有什么不同?

为方便起见,我在下面提供了我的实现的源代码(以及as a gist).到目前为止,我没有发现任何问题.它适用于我测试过的所有浏览器.

对于问题的不良描述我很抱歉,我不熟悉那个纯粹的事件部分.

var evento = (function (window) {
  var win = window
    , doc = win.document
    , _handlers = {}
    , addEvent
    , removeEvent
    , triggerEvent;

  addEvent = (function () {
    if (typeof doc.addEventListener === "function") {
      return function (el, evt, fn) {
        el.addEventListener(evt, fn, false);
        _handlers[el] = _handlers[el] || {};
        _handlers[el][evt] = _handlers[el][evt] || [];
        _handlers[el][evt].push(fn);

      };
    } else if (typeof doc.attachEvent === "function") {
      return function (el, evt, fn) {
        el.attachEvent(evt, fn);
        _handlers[el] = _handlers[el] || {};
        _handlers[el][evt] = _handlers[el][evt] || [];
        _handlers[el][evt].push(fn);
      };
    } else {
      return function (el, evt, fn) {
        el["on" + evt] = fn;
        _handlers[el] = _handlers[el] || {};
        _handlers[el][evt] = _handlers[el][evt] || [];
        _handlers[el][evt].push(fn);
      };
    }
  }());

  // removeEvent
  removeEvent = (function () {
    if (typeof doc.removeEventListener === "function") {
      return function (el, evt, fn) {
        el.removeEventListener(evt, fn, false);
        Helio.each(_handlers[el][evt], function (fun) {
          if (fun === fn) {
            _handlers[el] = _handlers[el] || {};
            _handlers[el][evt] = _handlers[el][evt] || [];
            _handlers[el][evt][_handlers[el][evt].indexOf(fun)] = undefined;
          }
        });

      };
    } else if (typeof doc.detachEvent === "function") {
      return function (el, evt, fn) {
        el.detachEvent(evt, fn);
        Helio.each(_handlers[el][evt], function (fun) {
          if (fun === fn) {
            _handlers[el] = _handlers[el] || {};
            _handlers[el][evt] = _handlers[el][evt] || [];
            _handlers[el][evt][_handlers[el][evt].indexOf(fun)] = undefined;
          }
        });
      };
    } else {
      return function (el, evt, fn) {
        el["on" + evt] = undefined;
        Helio.each(_handlers[el][evt], function (fun) {
          if (fun === fn) {
            _handlers[el] = _handlers[el] || {};
            _handlers[el][evt] = _handlers[el][evt] || [];
            _handlers[el][evt][_handlers[el][evt].indexOf(fun)] = undefined;
          }
        });
      };
    }
  }());

  // triggerEvent
  triggerEvent = function (el, evt) {
    _handlers[el] = _handlers[el] || {};
    _handlers[el][evt] = _handlers[el][evt] || [];

    for (var _i = 0, _l = _handlers[el][evt].length; _i < _l; _i += 1) {
      _handlers[el][evt][_i]();
    }
  };

  return {
    add: addEvent,
    remove: removeEvent,
    trigger: triggerEvent,
    _handlers: _handlers
  };
}(this));

最佳答案 我不关心你的系统是基于回调,事件还是lambda-calculus.对于你在这里公开的那一点,它似乎写得很好,并承诺做得很好(虽然我很好奇你如何处理removeEvent();)).

但是,我对您的实施有一些评论:

>每次添加事件处理程序时,都无需检查执行的浏览器.

每次他们打算给他们打电话时,我都会接受检查房产存在的人数,我感到很惊讶.在函数调用过程中没有人会将你的IE换成FF(任何愚蠢到足以定义除实际ECMA-5替换之外的document.addEventListener属性的人都应该被鞭打到死,如果你问我),所以检查你在开始时使用哪个平台并完成它,如下所示:

if (doc.addEventListener) {
    addEvent  = // ...
    freeEvent = // ...
}
else if (doc.attachEvent) {
    addEvent  =  // ...
    freeEvent =  // ...
}
/* etc. */

>您提供了一个统一的接口来附加处理程序,但是,根据您的代码将执行的浏览器,实际的处理程序将表现不同.

例如,在IE8中,事件的目标将无法以与ECMA-5约定相同的方式获得.

如果要提供真正的跨浏览器界面,则应为事件处理程序提供统一的执行上下文.
这可能包括一个“取消”功能,可以转换为:

cancel = function (e) { e.returnValue = false; }; // IE8-
cancel = function (e) { e.preventDefault();    }; // ECMA-5

你还应该将它恢复到IE8-下的目标对象,并统一target和event.target语义.

如果你真的想对程序员很好,你也可以解决一些奇怪的问题,比如说

>当图像已经被缓存时,IE8中没有触发的加载事件
>荒谬复杂的鼠标滚轮报告系统

可能还有其他几个.

我为自己的目的而做的方式是在实际处理程序周围生成一个包装器,它可以处理所有平台的特性并在调用实际用户代码之前建立一致的执行上下文.

最后一句话:除了它的美丽,我不太确定它是否仍然需要支持Netscape4风格的事件.但这是一个信仰问题,所以……

点赞