0

I'm trying to write a fake downloader which basically sleeps for certain interval and emits a 'downloaded' event. I also want to have my own variable that tracks the number of events emitted. This piece of code throws the following error:

ReferenceError: this is not defined

Code:

'use strict';
const EventEmitter = require('events');

class Downloader extends EventEmitter{
    constructor(){
        this.totalEmitted = 0;
    }
    download(delaySecs){
        setTimeout(() => {
            this.emit('downloaded',delaySecs);
            this.totalEmitted ++;
        },delaySecs*1000)
    }
}

module.exports = Downloader;

where as, if I comment this.totalEmitted, it works fine.

UPDATE:

When I completely eliminate the constructor it started working fine.

And even using an empty constructor is causing the this Reference error.

I'm not sure if the constructor is yet supported in node 4.4.5.

Work around:

'use strict';
const EventEmitter = require('events');

class Downloader extends EventEmitter{
    download(delaySecs){
        setTimeout(() => {
            if(this.totalEmitted == undefined) this.totalEmitted = 0;
            this.totalEmitted ++;
            this.emit('downloaded',delaySecs,this.totalEmitted);            
        },delaySecs*1000)
    }
}

module.exports = Downloader;
manikawnth
  • 2,739
  • 1
  • 25
  • 39
  • Don't use arrow functions if you need `this` inside them. Try to rewrite it into regular function – flppv Jun 11 '16 at 21:52
  • 1
    @vicodin, actually in this case not using an arrow function would cause issues. user3151330 wants the outer `this` (the `this` of `download`). A regular function would have to be bound or use a value from a higher scope to get to the `Downloader` instance in the `setTimeout` callback. – Noah Freitas Jun 11 '16 at 21:54
  • true, my apologies – flppv Jun 11 '16 at 21:59
  • 3
    have you tried add super() in your constructor? – james emanon Jun 11 '16 at 22:06
  • or add .bind(this) to the setTimeout? – james emanon Jun 11 '16 at 22:16
  • 1
    @jamesemanon you hit the bull's eye. Adding super is working. And it corresponds to the ES5 version of EventEmitter.call(this). But I still do not understand why javascript is not able to establish a this for the class itself. There is no such rule in ES6. – manikawnth Jun 11 '16 at 22:21
  • 1
    Inside a child class, `this` is not initialized until `super()` is called. – loganfsmyth Jun 11 '16 at 22:24
  • dang, I should of added it as an answer! lol.. I need those points! hahha.. glad to help! – james emanon Jun 11 '16 at 22:36
  • @loganfsmyth Even using an empty constructor in subclass throws this error. So, if I have to call a `super()` inside a sub class constructor to initialize this, why shouldn't Javascript automatically take care of it? What is the need of we writing it? – manikawnth Jun 11 '16 at 23:10
  • What if you want to pass different options to the parent class? – loganfsmyth Jun 12 '16 at 01:22

1 Answers1

0

If it doesn't bother you so much switching from ES6 Class to functions, then you could try:

'use strict';
const util = require('util');
const EventEmitter = require('events');

function Downloader() {
  var self = this;

  self.totalEmitted = 0;

  this.on('downloaded', function() {
    self.totalEmitted ++;
    console.log(self.totalEmitted);
  });
}

util.inherits(Downloader, EventEmitter);

Downloader.prototype.download = function(delaySecs) {
  setTimeout(() => {
      this.emit('downloaded', delaySecs);
  }, delaySecs*1000);
};

var downloader = new Downloader();
downloader.download(1);

module.exports = Downloader;