0
class MyExampleClass {
    constructor(port, service) {
        this.port = port;
        this.service = service;
        this.app = require('express')();
        this.http = require('http').createServer(this.app);
    }

    onListening() {
        // Current result: 'listening on port NaN for undefined'
        // Desired result: 'listening on port 3000 for test' (I want to CHANGE this behavior)
        console.log('listening on port %d for %s', this.port, this.service);

        // Current result: 'class: Server'
        // Desired result: 'class: Server' (I want to KEEP this behavior)
        console.log('class: ' + this.constructor.name);
    }

    start() {
        this.http.listen(this.port, this.onListening);
    }
}

const example = new MyExampleClass(3000, 'test');
example.start();

As stated in the comments of the onListening method, I want to access both the context of the instance of MyExampleClass and the callback instance of Server created by createServer.

3
  • A common technique is to put const self=this somewhere before the context switch and using self instead of this when referencing the other context
    – Dov Rine
    Commented Aug 27, 2019 at 6:27
  • @DovRine how would I do that cleanly if I have my callback as a separate method? Would I have to pass self in as another parameter to onListening or is there a better way so as not to alter the method signature?
    – Hank
    Commented Aug 27, 2019 at 6:29
  • I posted an answer that might help
    – Dov Rine
    Commented Aug 27, 2019 at 6:38

4 Answers 4

4

Bind this.onListening in the constructor to preserve the this context inside onListening.

You can't have this point to 2 different contexts so you will have to access the Server instance through this.http.

class MyExampleClass {
    constructor(port, service) {
        this.port = port;
        this.service = service;
        this.app = require('express')();
        this.http = require('http').createServer(this.app);

        this.onListening = this.onListening.bind(this);
    }

    onListening() {
        console.log('listening on port %d for %s', this.port, this.service);
        console.log('class: ' + this.http.constructor.name);
    }

    start() {
        this.http.listen(this.port, this.onListening);
    }
}

const example = new MyExampleClass(3000, 'test');
example.start();
7
  • The first call to log in onListening has the desired behavior, but not the second call to log. The second call now logs class: MyExampleClass.
    – Hank
    Commented Aug 27, 2019 at 6:56
  • @Hank then change this.constructor.name to this.http.constructor.name
    – Asaf Aviv
    Commented Aug 27, 2019 at 6:59
  • what do you expect to be printed out in the second log? this solution is correct, constructor.name is the name of the class Commented Aug 27, 2019 at 6:59
  • @AdamKosmala the question lists the desired and actual outputs that are printed.
    – Hank
    Commented Aug 27, 2019 at 7:00
  • @Hank You can't have this point to 2 different contexts, use this.http.constructor.name to access the Server instance
    – Asaf Aviv
    Commented Aug 27, 2019 at 7:01
2

Use arrow functions

class ExampleServer {
  constructor (port, service) {
    this.port = port
    this.service = service
    this.app = require('express')()
    this.http = require('http').createServer(this.app)
  }

  onListening = () => {
    console.log('listening on port %d for %s', this.port, this.service)
  }

  start = () => {
    this.http.listen(this.port, this.onListening)
  }
}

const server = new ExampleServer(3000, 'test')
server.start()
1
  • SyntaxError: Unexpected token =
    – Hank
    Commented Aug 27, 2019 at 6:48
2

Just use bind(this) on your callback reference like this this.http.listen(this.port, this.onListening.bind(this));

following the code will work


class ExampleServer {
    constructor(port, service) {
        this.port = port;
        this.service = service;
        this.app = require('express')();
        this.http = require('http').createServer(this.app);
    }

    onListening() {
        // I want to access the context for the instance of `ExampleServer`, but `this` is the context for the instance of `Server` created by `createServer`.
        console.log('listening on port %d for %s', this.port, this.service);

        // I want to also still be able to access the context for the instance of `Server` created by `createServer`, which is what the below is already doing.
        console.log(this.http.constructor);
    }

    start() {
        this.http.listen(this.port, this.onListening.bind(this));
    }
}

const server = new ExampleServer(3000, 'test');
server.start();
1
  • This doesn't give me the desired behavior that I want. See my edit to the question.
    – Hank
    Commented Aug 27, 2019 at 6:47
-4

How about something like this?

onListening(server=null) {
   const self = this;
        // I want to access the context for the instance of `ExampleServer`, but `this` is the context for the instance of `Server` created by `createServer`.
       if(server){
            console.log('listening on port %d for %s', server.port, server.service);
       }
        // I want to also still be able to access the context for the instance of `Server` created by `createServer`, which is what the below is already doing.
        console.log(self);
    }
5
  • This is bad design, for instance you can look @krishna's answer to solve it in a more elegant way. Commented Aug 27, 2019 at 6:44
  • @AlejandroGarciaAnglada: This is not bad design. See: Javascript var self = this; vs. .bind (gist.github.com/jashmenn/b306add36d3e6f0f6483)
    – Dov Rine
    Commented Aug 27, 2019 at 6:59
  • 1
    It's bad design in a sense that it just doesn't work. If you set self = this in the same context where you use self, it's exactly equivalent to just using this directly. The self = this must be done earlier, where the value of this is guaranteed to be what you want.
    – JJJ
    Commented Aug 27, 2019 at 7:07
  • @JJJ: My mistake. You are correct. Thanks for pointing it out.
    – Dov Rine
    Commented Aug 27, 2019 at 7:08
  • Correct, I was meaning what @JJJ said. Commented Aug 27, 2019 at 8:11

Not the answer you're looking for? Browse other questions tagged or ask your own question.