YUI has a useful event system. It is not perfect, but it is well designed and works without modifying Object.prototype. YUI is not based around XmlHttp and eval to load scripts. Why did they put it in a "util" package. Should've learned from Java's mistake.

The addListener function can take 1 extra arg. That is all you need. Just one. Pass in an object.

addListener( aDiv, "click", aDivClickHandler, someObject );
Dean Edwards wrote something like this. I wrote one, too a few years ago.

The only problem with these custom systems, is that none of them are autonomous. in all of the libraries mentioned this holds true.

What I mean is:

If callback A fires, it should fire autonomously of all other callbacks (C, D, E).

If callback A were to throw an error, the error would come back to the function which called fire() on the event. All of the callbacks after A would not fire. This is not autonomous and this is bad because one error in A can have devastating effects upon the entire callback list; it can cause an entire program to crash.
function err(){throw new Error('crap');}

function cool() { alert('yea'); }

addListener(document, "dblclick", err );
// If this event fires, 
// your event system's notifications are autonomous. 
// (not any I know).
addListener(document, "dblclick", cool );
What happens with addEventListener, is that callbacks are autonomous. In our example, if A had an error, the error would be thrown, C, D, and E would still fire.

function err(){throw new Error('crap');}

function cool() { alert('yea'); }

document.addEventListener("dblclick", err, false );
// this will fire; 
// DOM event notifications are autonomous.
document.addEventListener("dblclick", cool, false );
The solution to make a custom event notification autonomous is to use a new thread for each callback invocation in fire's loop.

This means that the library has to use setTimeout( "fn.call( o, ev )", 1 );

It is more resource intensive, but worth it. Autonomy is very important in a notification system.