Skip to content

Instantly share code, notes, and snippets.

@tbranyen
Created September 6, 2012 04:59
Show Gist options
  • Save tbranyen/3651431 to your computer and use it in GitHub Desktop.
Save tbranyen/3651431 to your computer and use it in GitHub Desktop.
Mixin-able events
// Portable & reusable Events object, not too different from what is found
// in Backbone.
//
// (Credits @visionmedia) & Modified from:
// https://raw.github.com/component/emitter/master/index.js
var Events = {
// Cache all callbacks.
callbacks: {},
// Listen on the given `event` with `fn`.
on: function(event, fn){
var callback = this.callbacks[event] = this.callbacks[event] || [];
callback.push(fn);
return this;
},
// Adds an `event` listener that will be invoked a single time then
// automatically removed.
once: function(event, fn){
var self = this;
function on() {
self.off(event, on);
fn.apply(this, arguments);
}
fn._off = on;
this.on(event, on);
return this;
},
// Remove the given callback for `event` or all registered callbacks.
off: function(event, fn){
var i;
var callbacks = this.callbacks[event];
if (!callbacks) {
return this;
}
// remove all handlers
if (arguments.length === 1) {
delete this.callbacks[event];
return this;
}
// remove specific handler
i = callbacks.indexOf(fn._off || fn);
if (~i) {
callbacks.splice(i, 1);
}
return this;
},
// Emit `event` with the given args.
emit: function(event){
var i, len;
var args = [].slice.call(arguments, 1);
var callbacks = this.callbacks[event];
if (callbacks) {
callbacks = callbacks.slice(0);
for (i = 0, len = callbacks.length; i < len; ++i) {
callbacks[i].apply(this, args);
}
}
return this;
},
// Return array of callbacks for `event`.
listeners: function(event){
return this.callbacks[event] || [];
},
// Check if this emitter has `event` handlers.
hasListeners: function(event){
return Boolean(this.listeners(event).length);
}
};
@tj
Copy link

tj commented Sep 6, 2012

you know i wouldn't hate if the interface was Emitter(Someother.prototype) in the first place, inheritance is a pretty fragile concept

@jdalton
Copy link

jdalton commented Dec 13, 2012

It would be nice if listeners() did return this.callbacks[event] || (this.callbacks[event] = []); so that devs holding the collection wouldn't have to grab it again once events are added.

@jdalton
Copy link

jdalton commented Dec 13, 2012

Keep in mind older browsers (IE < 9) lack Array#indexOf.

@jdalton
Copy link

jdalton commented Dec 13, 2012

Instead of [].slice in emit it would be rad to store a reference to slice instead. That literal is just more garbage to be collected.

@jdalton
Copy link

jdalton commented Dec 13, 2012

The use of ~i in off() isn't as clear as i < 0

@jdalton
Copy link

jdalton commented Dec 13, 2012

One optimization would be to avoid this binding by default.
See jsperf.com/avoiding-call

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment