Q: 写一个events,backbone或者jquery,包括on、off、once、trigger

A:

Author: @backbone @yeelan0319 @liyuk @bailnl

struct

this._events = {
    change: [callback_on_change1, callback_on_change2, ...],
    ...
}

on

Events.on = function(name, callback, context) {
    if (callback) {
      var handlers = events[name] || (events[name] = []);
      handlers.push({callback: callback, context: context, ctx: context || this});
      }
      return this;
};

off

Events.off = function(name, callback, context) {
    // 无参数清空所有
    if (!name && !callback && !context) {
        this._events = void 0;
        return this;
    }
    // 有name时,清空name对应
    if (!callback && !context) {
        delete this._events[name];
        continue;
    }
    // 有callback时检查
    var remaining = [];
    if(
        callback && callback !== handler.callback &&
        callback !== handler.callback._callback ||
        context && context !== handler.context
    ){
        //保留回调函数在数组中
    }
}

trigger

//当绑定3个以下回调函数的时候Backbone会做如下优化处理,据说这样是可以提高执行效率的。    
var triggerEvents = function(events, args) {
    var ev, i = -1, l = events.length, a1 = args[0], a2 = args[1], a3 = args[2];
    switch (args.length) {
      case 0: while (++i < l) (ev = events[i]).callback.call(ev.ctx); return;
      case 1: while (++i < l) (ev = events[i]).callback.call(ev.ctx, a1); return;
      case 2: while (++i < l) (ev = events[i]).callback.call(ev.ctx, a1, a2); return;
      case 3: while (++i < l) (ev = events[i]).callback.call(ev.ctx, a1, a2, a3); return;
      default: while (++i < l) (ev = events[i]).callback.apply(ev.ctx, args); return;
    }
};

once

var once = _.once(function(){
    self.off(name, once);
    callback.apply(this, arguments);
});
return this.on(name, once, context);

Roast:

  • Events的引入减少了callback的层级调用。
  • 解耦,一对多的关系。 这个问题是一个基本概念,但不要因为简单而忽视了这个基本概念。