根据浏览器支持,有 3 种方法可以实现这一点。
1) EventTarget 现在是可构造的,所以只需扩展它:
class MyEventTarget extends EventTarget {
constructor(){
super()
}
}
2) DOM 'Node' 接口实现了 EventTarget,所以只需实现它:
function MyEventTarget(){
var target = document.createTextNode(null);
this.addEventListener = target.addEventListener.bind(target);
this.removeEventListener = target.removeEventListener.bind(target);
this.dispatchEvent = target.dispatchEvent.bind(target);
}
MyEventTarget.prototype = EventTarget.prototype;
3)推出自己的(假设没有选项arg)并调度异步:
function MyEventTarget(){
this.__events = new Map();
}
MyEventTarget.prototype = {
addEventListener(type, listener){
var listeners = this.__events.get(type);
if(!listeners){
listeners = new Set();
this.__events.set(type, listeners);
}
listeners.add(listener);
},
removeEventListener(type, listener){
var listeners = this.__events.get(type);
if(listeners){
listeners.delete(listener);
if(listeners.size === 0){
this.__events.delete(type);
}
}
},
dispatchEvent(event){
var listeners = this.__events.get(event.type);
if(listeners){
for(let listener of listeners){
setTimeout(listener.call(null, event), 0);
}
}
}
}
如果需要,将 Map()/Set() 替换为 {}/[]。
所有这 3 个选项都可以通过以下方式进行测试:
var target = new MyEventTarget();
target.addEventListener('test', (e) => {console.log(e.detail);}, false);
var event = new CustomEvent('test', {detail : 'My Test Event'});
target.dispatchEvent(event);
任何需要实现您自己的“EventTarget”接口的对象都可以像原生接口一样继承它:
function Person(name){
MyEventTarget.call(this);
this.__name = name;
}
Person.prototype = {
__proto__ : MyEventTarget.prototype,
get name(){ return this.__name;}
}