9

I want some predefined custom listeners, that are defined already with the definition of the class (like the build in 'newListner' event). So I don't want to just bind them in the constructor because it would be executed on every new instance of that class.

How to do this? Modify the prototype? Is it possible at all?

What I have so far:

class Cat extends EventEmitter {
  // just added for demonstration, I don't want this!
  constructor() {
    super();
    // does fire
    this.on('wave', function() { console.log('constructor wave'); });
  }
}
// compiles but does not fire
Cat.prototype.on('wave', function() { console.log('prototype wave'); });

var cat = new Cat();
cat.emit('wave');
flori
  • 14,339
  • 4
  • 56
  • 63
  • The constructor is part of the class definition? This doesn't really make sense. Only instances can have listeners and fire events, so this is really the only way - register them for every instance. – Bergi Mar 04 '16 at 13:29
  • @Bergi Was a bit misleading, moved and changed the comment. The constructor is of course not part of the definition, that is why I don't want it. – flori Mar 04 '16 at 14:03
  • What constitutes a "class definition" then for you, if not the `class` declaration that contains the constructor? – Bergi Mar 04 '16 at 14:06
  • @Bergi With _class definition_ I mean everything that is already there before the constructor is called, that is "executed" only once (at definition time) and not with every new instance. In other languages that could be class properties. ES6 does not have them, so I wondered if there is any other solution or if I missed something. – flori Mar 04 '16 at 14:19

2 Answers2

9

You cannot avoid registering the listeners separately for every instance, and the natural place to do that is in the constructor1, 2. However, you can avoid creating new listener functions:

class Cat extends EventEmitter {
  constructor() {
    super();
    this.on('wave', this.onWave);
  }
  onWave() {
    console.log('prototype wave');
  }
}

var cat = new Cat();
cat.emit('wave');

1: There are other ways, like a getter for ._events. You could do all kinds of fancy stuff with that, including prototypical inheritance for "default" listeners, but those are totally overcomplicated and get over your head quickly. You can do fancy things as well - and much cleaner - by just putting some generic code in the constructor.
2: You could also override (specialise) the init method of EventEmitters, but it comes down to exactly the same.

Bergi
  • 630,263
  • 148
  • 957
  • 1,375
0

Since, as far as I can see, multiple instances of the Cat emitter can't communicate with each other, you will have to register the listener for each instance in the constructor:

class Cat extends EventEmitter {
  constructor() {
    super();
    this.on('wave', function() { console.log('constructor wave'); });
  }
}

var cat = new Cat();
cat.emit('wave');

You can then always share your emitter instance throughout different files by requireing it into the scripts you need it in.

nils
  • 25,734
  • 5
  • 70
  • 79
  • `Cat.prototype` is `instanceof EvenEmitter`, and you could theoretically do `Cat.prototype.emit('wave')`, but you're right that it doesn't make any sense. – Bergi Mar 04 '16 at 13:34
  • Thank you for clarifying. `Cat.prototype.emit('wave')` doesn't seem to work, so I assumed there are things happening in the `EventEmitter` constructor that are necessary for it to work (which is only called when a new `Cat` intance is created). Is that correct? – nils Mar 04 '16 at 13:37
  • [Last time I checked](http://stackoverflow.com/a/22791445/1048572) it was not necessary to invoke the constructor (but the best practise, of course), `on` and `emit` calls would initialise the object themselves if it hasn't happened yet. – Bergi Mar 04 '16 at 13:42
  • Thank you, that makes sense. – nils Mar 04 '16 at 13:45