4

Using the eventBus pattern in Vue.js allows a central place to emit events so that subscribing listening components can handle such events.

The below code snippets are setting up listeners on child components to receive an updated Object server when a particular UI change happens.

I ran into something today where this DID'T work in a child component:

created: function() {
        eventBus.$on('serverSelected', function(server) {
            console.log('serverDetails, server=' + server.toString());
            this.server = server;
    });
},

but this DID work:

created: function() {
        eventBus.$on('serverSelected', (server) => {
            console.log('serverDetails, server=' + server.toString());
            this.server = server;
    });
},

I believe the only different is the ES6 syntax for the callback. But the vanilla JS should still work right?

I'm very new to JS. Why is there a different and why does only the second version work?

lollercoaster
  • 15,969
  • 35
  • 115
  • 173

1 Answers1

3

A major difference between function(){} and () => {} is precisely how this will be handled inside the scope of the function.

With the arrow function (() => {}), this will be handled lexically; meaning it will point to the containing scope.

From the MDN documentation linked above,

An arrow function does not create its own this context, so this has its original meaning from the enclosing context

With the regular function expression, what this refers to depends on how the method is called. In your case it probably refers to eventBus.

Again, from the MDN documentation,

Until arrow functions, every new function defined its own this value (a new object in the case of a constructor, undefined in strict mode function calls, the context object if the function is called as an "object method", etc.).

That's why it works with the arrow function, but not with the regular function, because with the arrow function, this points to the Vue that has the server property, and with the regular function, it points to the eventBus.

Here is an example showing the difference. Pop open the console to see the different messages.

If you wanted to continue to use the regular function, you would need to bind this appropriately. One way is to use bind.

created: function() {
        eventBus.$on('serverSelected', function(server) {
            console.log('serverDetails, server=' + server.toString());
            this.server = server;
    }.bind(this));
},

Or you could use a closure.

created: function() {
        const self = this
        eventBus.$on('serverSelected', function(server) {
            console.log('serverDetails, server=' + server.toString());
            self.server = server;
    });
},

See also, How to access the correct this inside a callback?

Bert
  • 80,741
  • 17
  • 199
  • 164