2

I am trying to understand how Facebook Flux works by looking at the source code of their flux chat example.

There, I saw this code:

var MessageStore = assign({}, EventEmitter.prototype, {

  emitChange: function() {
    this.emit(CHANGE_EVENT);
  },

  /**
   * @param {function} callback
   */
  addChangeListener: function(callback) {
    this.on(CHANGE_EVENT, callback);
  },
  ...
}

...

module.exports = MessageStore;

...where assign is just polyfilled Object.assign from ES6 spec.

Hm. Would this code, using classes and extends instead, work? Would it mean the same thing? What are differences and advantages/disadvantages of this approach?

class MessageStore extends EventEmitter {
    emitChange() {
        this.emit(CHANGE_EVENT);
    }

    addChangeListener(callback) {
        this.on(CHANGE_EVENT, callback);
    }

    ...
}

module.exports = new MessageStore();

I am asking, because, coming from other languages, I intuitively understand class/extends, while prototype-based inheritance is always a little unclear to me.

Karel Bílek
  • 36,467
  • 31
  • 94
  • 149
  • `Object.assign` only copies properties, there is no inheritance. – Oriol Jan 02 '16 at 00:25
  • But the code, as I wrote it, should be equivalent, no? Maybe except for the one class that is created and used only once. – Karel Bílek Jan 02 '16 at 00:27
  • Similar, but *not* identical, question - https://stackoverflow.com/questions/29548562/is-es6-class-extend-fully-equivalent-to-object-assign-based-extending-of-an-obje – Karel Bílek Jan 02 '16 at 00:30
  • That depends on whether `EventEmitter.prototype` will be modified. If you want inheritance, also consider using `Object.assign(Object.create(EventEmitter.prototype), {...})` – Oriol Jan 02 '16 at 00:34
  • Hm. Both codes would do the same if the `EventEmitter.prototype` was modified, no? – Karel Bílek Jan 02 '16 at 00:40
  • Another similar question: http://stackoverflow.com/questions/19965844/lodash-difference-between-extend-assign-and-merge – el3ati2 Jan 02 '16 at 00:41

2 Answers2

3

Here is working code that you can use with regards to ES6 syntax and your situation:

import EventEmitter from 'events';
const CHANGE_EVENT = 'change';

class MessageStore extends EventEmitter {

  constructor() {
    super();
  }

  addChangeListener = (callback) => {
    this.on(CHANGE_EVENT, callback);
  }

  removeChangeListener = (callback) => {
    this.removeListener(CHANGE_EVENT, callback);
  }

  emitChange = () => {
    this.emit(CHANGE_EVENT);
  }

}

Note, I prefer the ES6 function literal syntax because it ensures that "this" is always bound to the enclosing object context.

For a fully working ES6 store example, please feel free to review the stores code in my Babel React Starter App

This is also a useful reference on ES6 classes that visually explains what is going on inside the body of a class definition.

arcseldon
  • 35,523
  • 17
  • 121
  • 125
  • I don't get the function literal syntax. How would it be different without it? `this` will refer to the object even when it is a normal function, as in my question, no? – Karel Bílek Jan 02 '16 at 13:41
  • @KarelBílek - you are right here. However, more generally, have been bitten other times eg with "helper functions" extending from React.Component. - a common pattern you see is the need to explicitly bind to the function you use eg "onPress={this.onLoginPressed.bind(this)}" However, if you declare your onLoginPressed function using above syntax eg. onLoginPressed = () => { console.log('Attempting to log in with username ' + this.state.username); } then you no longer need to bind explicity. eg. simply use "onPress={this.onLoginPressed}" as a result, prefer this syntax so no doubts. – arcseldon Jan 03 '16 at 02:08
0

class extends:* You are extending a generic class, which is sometimes exactly what you want, e.g. a button extends a domElement, but a button should not extend an EventEmitter because they have nothing in common.

Object.assign: With Object.assign you are "mixin" a new functionality into the target object, e.g. a Store may mixin an EventEmitter. In Java you would use Store implements EventEmitter which is a bit more self explaining.

RiZKiT
  • 2,107
  • 28
  • 23