4

While reading the docs for NodeJS at https://nodejs.org/api/events.html, I am a bit confused about this area of handling this in event listeners:

“It is possible to use ES6 Arrow Functions as listeners, however, when doing so, the this keyword will no longer reference the EventEmitter instance:”

const myEmitter = new MyEmitter();
myEmitter.on('event', (a, b) => {
  console.log(a, b, this);
  // Prints: a b {}
});
myEmitter.emit('event', 'a', 'b');

The object that this represents is empty. What does this reference in the arrow function, please?

decahub
  • 78
  • 2
  • 11
  • 1
    `this` binding has been dropped in arrow functions. Its supposed to make it easier to fallow an oop style. – mattdevio May 06 '17 at 19:35
  • 2
    Arrow functions share the same context as that of the enclosing scope. Use proper functions in the case. – shanks May 06 '17 at 19:35

3 Answers3

4

Until arrow functions, every new function defined its own this value. This proved to be annoying with an object-oriented style of programming.

An arrow function does not create its own this context, so this has its original meaning from the enclosing context. Thus, the following code works as expected:

function Person(){
  this.age = 0;

  setInterval(() => {
    this.age++; // |this| properly refers to the person object
  }, 1000);
}

var p = new Person();

For more details check here and here too.

You can bind this to arrow functions, Try binding this by-

myEmitter.on('event', (a, b) => {
  console.log(a, b, this);
  // Prints: a b {}
}.bind(this));
optimistanoop
  • 912
  • 1
  • 11
  • 14
  • 1
    Thanks for your response. I understand the context of `this`. I am just wondering why it is an empty object. I was thinking `this` would refer to a global object, but that is not the case. In the example that shambalambala gave us, within the IIFE, `this` is `undefined`. – decahub May 06 '17 at 20:36
2

As shanks noted in comments, this in the arrow function represents the context of the scope which encloses the arrow function.

Here's an example:

const EventEmitter = require('events')
const myEmitter = new EventEmitter();

this.foo = "bar";

myEmitter.on('event', () => {
  console.log(this); // { foo: "bar" }
});

(function() {
  this.foo = "baz";
  myEmitter.emit('event');
})();
Aurélien Gasser
  • 3,043
  • 1
  • 20
  • 25
  • Thanks for your response. When using "strict mode", a TypeError is thrown saying `TypeError: Cannot set property 'foo' of undefined` – decahub May 06 '17 at 20:32
1

Doing further research:

this in a module script refers to exports within the module scope. this in the REPL refers to the global object.

Looking at shambalambala answer. this within an IIFE in Strict Mode is undefined and in Standard Mode it is the global object.

From: Why console.log(this) in node return empty object? by T.J. Crowder

Because NodeJS runs your code in a module, and this references the object it creates for your module's exports (which is also the exports property on the module variable it provides you). (As they don't really mention that in the module documentation, I suspect using it is probably not a great idea — use exports instead.)

But your code calling the IIFE calls it with this referring to the global object, because in loose (non-strict) mode, calling a normal function not through an object property calls it with this set to the global object. (In strict mode, this would be undefined there.)

Why does this become undefined within the IIFE in Strict mode?

From: Why is "this" in an anonymous function undefined when using strict? by jAndy

It's because, until ECMAscript 262 edition 5, there was a big confusion if people who where using the constructor pattern, forgot to use the new keyword. If you forgot to use new when calling a constructor function in ES3, this referenced the global object (window in a browser) and you would clobber the global object with variables.

That was terrible behavior and so people at ECMA decided, just to set this to undefined.

Community
  • 1
  • 1
decahub
  • 78
  • 2
  • 11