Skip to content

Instantly share code, notes, and snippets.

@menixator
Last active August 29, 2015 14:08
Show Gist options
  • Save menixator/d192e29dccd99a169bf2 to your computer and use it in GitHub Desktop.
Save menixator/d192e29dccd99a169bf2 to your computer and use it in GitHub Desktop.
Yet another EventEmitter library

#EventEmitter.js

Create:

  • Using constructor:
var emitter = new EventEmitter();
  • Merging with an object.
var emitter = EventEmitter.extend({});
  • Inheriting:
EventEmitter.extend(Emitter);
function Emitter(){}

##Listen:

  • Basic:
emitter.on('some_event', function(data, eventName){
	console.log("'%s' has been triggered with data: ", eventName);
})
  • Multiple events:
emitter.on('some_event, some_other_event', function(data, eventName){
	console.log("'%s' has been triggered with data: ", eventName);
})
  • Multiple listeners:
emitter.on('some_event', function(data, eventName){
	console.log("#1 - '%s' has been triggered with data: ", eventName);
}, function(data, eventName){
	console.log("#2 - '%s' has been triggered with data: ", eventName);
});

// this works too:
emitter.on('some_event', [function(data, eventName){
	console.log("#1 - '%s' has been triggered with data: ", eventName);
}, function(data, eventName){
	console.log("#2 - '%s' has been triggered with data: ", eventName);
}]);

##Trigger:

  • Basic:
emitter.trigger('some_event', {value: 300});
  • Multiple events:
emitter.trigger('some_event, some_other_event', {value: 300});

##Remove:

Single:

emitter.off('some_event'); // all the listeners are removed.
emitter.off('some_event', someFunction);

Multiple:

emitters.off('some_event, someother_event', functionName);
emitters.off('some_event', [functionName, someOtherFunctionName]);
var EventEmitter = (function() {
EventEmitter.name = 'EventEmitter';
function EventEmitter() {}
/**
* Event listener storage array.
* @type {Array}
*/
EventEmitter.prototype.__events__ = [];
/**
* for Slicing arguments
* @type {Function}
*/
var arrSlice = [].slice;
/**
* Checks if `o` is an array
* @param {()} o
* @return {Boolean} is o an Array?
*/
var isArray = function(o) {
return Object.prototype.toString.call(o) === '[object Array]';
};
/**
* Gets the functions contained within `arr`. doesn't matter if it's in really deep.
* @param {Array} arr
* @return {Array} Array of functions
*/
EventEmitter.getListeners = function(arr, g) {
var gathered = g || [];
arr.forEach(function(fn){
if (typeof fn == 'function'){
gathered.push(fn);
return null;
} else if (isArray(fn)){
return EventEmitter.getListeners(fn, gathered);
}
});
return gathered;
};
/**
* Normalizes and splits the namespaces. A comma is used to separate multiple namespaces.
* @param {String} str
* @return {Array}
*/
EventEmitter.getNamespaces = function(str) {
return str.trim().split(/\s*,\s*/).filter(function(nsp) {
return nsp !== '';
});
};
/**
* Add an event listener.
* @param {String} nsp namespace(s)
* @param {Array/Function} listener(s) The listeners. Any function that follows the nsp argument.
*/
EventEmitter.prototype.on = function(nsp) {
var listeners = EventEmitter.getListeners(arrSlice.call(arguments, 1));
EventEmitter.getNamespaces(nsp).forEach(function(name) {
listeners.forEach(function(fn) {
this.__events__.push({
name: name,
listener: fn
});
}.bind(this));
}.bind(this));
return this;
};
/**
* Trigger an event.
* @param {String} nsp
* @param {*} data data
*/
EventEmitter.prototype.trigger = function(nsp, data) {
var events = this.__events__;
var nsps = EventEmitter.getNamespaces(nsp);
nsps.has = function(nsp) {
return !!~nsps.indexOf(nsp);
};
var ev;
for (var i = events.length; i-- > 0;) {
ev = events[i];
if (nsps.has(ev.name)) {
ev.listener(data, nsp);
}
}
return this;
};
/**
* Add an event emitter that will remove itself after a call.
* @param {String} event event name(s)
*/
EventEmitter.prototype.once = function(event) {
var self = this;
var listeners = EventEmitter.getListeners(arrSlice.call(arguments, 1)).map(function(fn) {
var once = function(data, ev) {
fn(data, ev);
self.off(event, once);
return null;
};
return once;
});
return this.on.apply(this, [event].concat(listeners));
};
/**
* Removes an event emitter
* @param {String} nsp namespace(s)
*/
EventEmitter.prototype.off = function(nsp) {
var events = this.__events__;
var nsps = EventEmitter.getNamespaces(nsp);
if (nsp.length === 0) {
throw new Error("no event names.");
}
nsps.has = function(nsp) {
return !!~nsps.indexOf(nsp);
};
var listeners = EventEmitter.getListeners(arrSlice.call(arguments, 1));
listeners.any = listeners.length > 0;
listeners.has = function(fn) {
return !!~listeners.indexOf(fn);
};
var ev;
for (var i = events.length; i-- > 0;) {
ev = events[i];
if (nsp === '*' || nsps.has(ev.name)) {
if (listeners.any) {
if (listeners.has(ev.listener)) {
events.splice(i, 1);
}
} else {
events.splice(i, 1);
}
}
}
return this;
};
/**
* Extends the class to another function or mix in the class's functions into an object.
* @param {Function/Object} obj
* @return {Object}
*/
EventEmitter.extend = function(obj) {
if ('object' === typeof obj && obj !== null) {
var o = new EventEmitter();
for (var key in o) {
if (Object.prototype.hasOwnProperty.call(o, key)) {
obj[key] = o[key];
}
}
return obj;
} else if ('function' === typeof obj) {
obj.prototype = Object.create(EventEmitter.prototype, {
constructor: {
value: obj
}
});
return obj;
} else {
return new EventEmitter();
}
};
return EventEmitter;
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment