There are two ways to implement the EventTarget "Interface".
1) Like mdn suggests use javascript prototypes. In my opinion this is clearly not the best approach to do this. The simple reason is that everybody who does use your library has to know that he needs to add a listeners property to his constructor function.
function implement_event_target_interface(target_constructor_function)
{
target_constructor_function.prototype.listeners = null;
target_constructor_function.prototype.addEventListener = function(type, callback) {
if (!(type in this.listeners)) {
this.listeners[type] = [];
}
this.listeners[type].push(callback);
};
target_constructor_function.prototype.removeEventListener = function(type, callback) {
if (!(type in this.listeners)) {
return;
}
var stack = this.listeners[type];
for (var i = 0, l = stack.length; i < l; i++) {
if (stack[i] === callback){
stack.splice(i, 1);
return;
}
}
};
target_constructor_function.prototype.dispatchEvent = function(event) {
if (!(event.type in this.listeners)) {
return true;
}
var stack = this.listeners[event.type].slice();
for (var i = 0, l = stack.length; i < l; i++) {
stack[i].call(this, event);
}
return !event.defaultPrevented;
};
}
let Person = function()
{
this.listeners = {}; // Every contructor that implements the event_target_interface must have this property. This is not very practical and intuitive for the library-user.
this.send_event = function() {
var event = new CustomEvent('test_event', { 'detail': "test_detail" });
this.dispatchEvent(event);
}
}
implement_event_target_interface(Person);
let person = new Person();
person.addEventListener('test_event', function (e) {
console.log("catched test_event from person")
}.bind(this), false);
person.send_event();
And not only that, it gets even worse when you use constructor inheritance on Person, because you also need to inherit the prototype in order to be able to send events.
let Student = function() {
Person.call(this);
}
Student.prototype = Person.prototype;
Student.prototype.constructor = Student;
let student = new Student();
student.addEventListener('test_event', function (e) {
console.log("catched test_event from student")
}.bind(this), false);
student.send_event();
2) Use constructor inheritance. Much much better.
function EventTarget()
{
this.listeners = {};
this.addEventListener = function(type, callback) {
if (!(type in this.listeners)) {
this.listeners[type] = [];
}
this.listeners[type].push(callback);
};
this.removeEventListener = function(type, callback) {
if (!(type in this.listeners)) {
return;
}
var stack = this.listeners[type];
for (var i = 0, l = stack.length; i < l; i++) {
if (stack[i] === callback){
stack.splice(i, 1);
return;
}
}
};
this.dispatchEvent = function(event) {
if (!(event.type in this.listeners)) {
return true;
}
var stack = this.listeners[event.type].slice();
for (var i = 0, l = stack.length; i < l; i++) {
stack[i].call(this, event);
}
return !event.defaultPrevented;
};
}
let Person = function()
{
EventTarget.call(this);
this.send_event = function() {
var event = new CustomEvent('test_event', { 'detail': "test_detail" });
this.dispatchEvent(event);
}
}
let person = new Person();
person.addEventListener('test_event', function (e) {
console.log("catched test_event from person")
}.bind(this), false);
person.send_event();
Emitter.prototype = Object.create(Emitter.prototype, …)- wait, what?EventTargetis just an interface, not a constructor. Also, you cannot inherit from native DOM structures.Object.createline sets up the prototype and the proper constructor. It was an attempt to inherit from the EventTarget "class".EventTarget, but fromEmitteritself…