import { Disposable } from '../types' ; see https param { Function } fn param { * } context param { Boolean } once constructor private class EE { constructor ( public fn , public context , public once ) { this . once = once || false ; } } constructor public export class EventEmitter { private _events : Record < string , any > ; private _eventsCount : number ; constructor ( ) { this . _events = Object . create ( null ) ; this . _eventsCount = 0 ; } emit ( evt , a1 ? , a2 ? , a3 ? , a4 ? , a5 ? ) { if ( ! this . _events [ evt ] ) return false ; const listeners = this . _events [ evt ] ; const len = arguments . length ; let args ; let i ; if ( listeners . fn ) { if ( listeners . once ) this . off ( evt , listeners . fn , undefined , true ) ; switch ( len ) { case 1 : return listeners . fn . call ( listeners . context ) , true ; case 2 : return listeners . fn . call ( listeners . context , a1 ) , true ; case 3 : return listeners . fn . call ( listeners . context , a1 , a2 ) , true ; case 4 : return listeners . fn . call ( listeners . context , a1 , a2 , a3 ) , true ; case 5 : return listeners . fn . call ( listeners . context , a1 , a2 , a3 , a4 ) , true ; case 6 : return listeners . fn . call ( listeners . context , a1 , a2 , a3 , a4 , a5 ) , true ; } for ( i = 1 , args = new Array ( len - 1 ) ; i < len ; i ++ ) { args [ i - 1 ] = arguments [ i ] ; } listeners . fn . apply ( listeners . context , args ) ; } else { const length = listeners . length ; let j ; for ( i = 0 ; i < length ; i ++ ) { if ( listeners [ i ] . once ) this . off ( evt , listeners [ i ] . fn , undefined , true ) ; switch ( len ) { case 1 : listeners [ i ] . fn . call ( listeners [ i ] . context ) ; break ; case 2 : listeners [ i ] . fn . call ( listeners [ i ] . context , a1 ) ; break ; case 3 : listeners [ i ] . fn . call ( listeners [ i ] . context , a1 , a2 ) ; break ; case 4 : listeners [ i ] . fn . call ( listeners [ i ] . context , a1 , a2 , a3 ) ; break ; default : if ( ! args ) { for ( j = 1 , args = new Array ( len - 1 ) ; j < len ; j ++ ) { args [ j - 1 ] = arguments [ j ] ; } } listeners [ i ] . fn . apply ( listeners [ i ] . context , args ) ; } } } return true ; } on ( evt , fn , context ? , once = false ) { if ( typeof fn !== 'function' ) { throw new TypeError ( 'The listener must be a function' ) ; } const listener = new EE ( fn , context || this , once ) ; if ( ! this . _events [ evt ] ) this . _events [ evt ] = listener , this . _eventsCount ++ ; else if ( ! this . _events [ evt ] . fn ) this . _events [ evt ] . push ( listener ) ; else this . _events [ evt ] = [ this . _events [ evt ] , listener ] ; return { dispose : this . off . bind ( this , evt , fn ) } ; } once ( event , fn , context ? ) { return this . on ( event , fn , context , true ) ; } off ( evt , fn ? , context ? , once ? ) { if ( ! this . _events [ evt ] ) return this ; if ( ! fn ) { this . clearEvent ( evt ) ; return this ; } const listeners = this . _events [ evt ] ; const events = [ ] ; if ( listeners . fn ) { if ( listeners . fn === fn && ( ! once || listeners . once ) && ( ! context || listeners . context === context ) ) { this . clearEvent ( evt ) ; } } else { for ( let i = 0 , length = listeners . length ; i < length ; i ++ ) { if ( listeners [ i ] . fn !== fn || ( once && ! listeners [ i ] . once ) || ( context && listeners [ i ] . context !== context ) ) { events . push ( listeners [ i ] ) ; } } if ( events . length ) this . _events [ evt ] = events . length === 1 ? events [ 0 ] : events ; else this . clearEvent ( evt ) ; } return this ; } removeAllListeners ( evt ? ) { if ( evt ) { if ( this . _events [ evt ] ) this . clearEvent ( evt ) ; } else { this . _events = Object . create ( null ) ; this . _eventsCount = 0 ; } return this ; } private clearEvent ( evt ) { if ( -- this . _eventsCount === 0 ) this . _events = Object . create ( null ) ; else delete this . _events [ evt ] ; } }