diff --git a/src/event/Evented.js b/src/event/Evented.js index 67bc848..e058291 100644 --- a/src/event/Evented.js +++ b/src/event/Evented.js @@ -20,10 +20,7 @@ */ var Trait = require( 'easejs' ).Trait, - isArray = require( '../std/Array' ).isArray, - - // used for hiding cached event indexes - _evid = Symbol(); + isArray = require( '../std/Array' ).isArray; /** @@ -55,6 +52,26 @@ module.exports = Trait( 'Evented', */ _gaps: {}, + /** + * Private listener metadata field + * @type {Symbol} + */ + _evid: null, + + + /** + * Prepare private listener metadata field + * + * The event identifier field is set on registered listeners to provide + * constant-time lookups when querying for listener indexes or status. + * + * @O {1} constant time + */ + __mixin() + { + this._evid = Symbol(); + }, + /** * Defines a list of events by unique identifier @@ -226,7 +243,8 @@ module.exports = Trait( 'Evented', 'virtual protected hookEvent'( ev, listener ) { let evls = this._events[ ev ], - avail = this._gaps[ ev ].pop(); + avail = this._gaps[ ev ].pop(), + _evid = this._evid; if ( listener[ _evid ] === undefined ) { @@ -262,7 +280,7 @@ module.exports = Trait( 'Evented', */ hooksEvent( ev, listener ) { - let levdata = listener[ _evid ]; + let levdata = listener[ this._evid ]; return !!( levdata && ( levdata[ ev ] !== undefined ) ); }, @@ -307,7 +325,7 @@ module.exports = Trait( 'Evented', } let evls = this._events[ ev ], - levdata = listener[ _evid ] || {}, + levdata = listener[ this._evid ] || {}, index = levdata[ ev ]; // this is important, since we (a) cannot necessarily trust that the diff --git a/test/event/EventedTest.js b/test/event/EventedTest.js index 405f069..f51b729 100644 --- a/test/event/EventedTest.js +++ b/test/event/EventedTest.js @@ -646,5 +646,28 @@ describe( 'event.Evented', () => expect( stub.hooksEvent( ev2, f2 ) ).to.be.true; } ); } ); + + + describe( 'listener metadata', () => + { + /** + * It is important that each Evented instance store its listener + * metadata in a distinct field; otherwise, they would query + * each-other, which would produce conflicts if the events happen to + * have the same name (which would not be uncommon). + */ + it( 'is not accessible to other Evented instances', () => + { + var ev = 'foo', + f = () => {}; + + // this would fail if data were shared because the system would + // consider f to have already been registered with event `foo' + [ stub, EvStub() ].forEach( s => + s.evDefineEvents( [ ev ] ) + .on( ev, f ) + ); + } ); + } ); } );