In effetti hai perfettamente ragione.
Mi sono creato una funzione che oltre a permettere di aggiungere listener in modo crossbrowser ( risolvendo in IE il problema del this e dei listeners eseguiti in ordine arbitrario ) tiene traccia di tutti i listener aggiunti. In questo modo al posto di FireEvent o dispatchEvent uso una funzione che cicla tutti i listener e li esegue.
Ne avevo creata una versione standalone tempo fa:
codice:
function $addListener(obj, ev, lis) {
	if(!obj.events) obj.events = {}
	if(!obj.events[ev]) obj.events[ev] = [];
	obj.events[ev].push(lis);
	if(obj.addEventListener)
		obj.addEventListener(ev, lis, 0);
	else if(obj.attachEvent && !obj.events.iefix) {
		obj.events.iefix = true;
		obj.attachEvent("on" + ev, function() {
			$callListeners(obj, ev);
		});
	}
}

function $callListeners(obj, ev) {
	for(var i = 0, l = obj.events[ev].length; i!=l; i++) {
		obj.events[ev][i].call(obj);
	}
}


window.onload = function() {
  var el =document.getElementsByTagName("body")[0];
  $addListener(el, "click", function() { alert(this.nodeType + this.events.click); });
  $addListener(el, "click", function() { alert(this.tagName); });
}