0

function Device(socket) {

  this.imei = false;
  this.status = false; //maintaining the logged in status
  let self = this; //saving this variable

  this.on('data', function() { //Event on the device object

    //I want to access self.imei

  });

  Device.prototype.saveLocation = function(parts) {
    //Here the value of self changes to the value of self of the recent object created
    console.log("In save location : IMEI " + self.imei);


  };
}

I am creating new objects of the device class and wanted to save the 'this' value of every object to self variable so that I can use that in callbacks without any hassle. But what is happening is that when two objects a and b are created, the value of self of object a also changes to that of b which produces ambigous results. Can someone explain why? New devices that connect to the server, changes the self value of every previous object.

const server = net.createServer(function (socket) {
    socket.name = socket.remoteAddress + ":" + socket.remotePort;
    socket.device = new Device(socket);
    clients.push(socket);
    let bufferString = 'cddwcdc';
    socket.emit('data',bufferString);
});
Barmar
  • 741,623
  • 53
  • 500
  • 612
Abhishek Yadav
  • 342
  • 1
  • 2
  • 16
  • 2
    Possible duplicate of [How to access the correct \`this\` inside a callback?](https://stackoverflow.com/questions/20279484/how-to-access-the-correct-this-inside-a-callback) – Andreas Aug 31 '18 at 16:19
  • Can you include the code where you are creating the new `Device` objects? – Jimenemex Aug 31 '18 at 16:19
  • `Device.prototype.saveLocation` is not in the scope of the `Device()` function that contains `self`. – Barmar Aug 31 '18 at 16:20
  • You don't need to use `self` in `saveLocation`. When you call `someDevice.saveLocation()`, it receives `someDevice` in `this`. – Barmar Aug 31 '18 at 16:23
  • @Barmar But ithe self variable still has some value, which is equal to the latest object created, is it due to closure? – Abhishek Yadav Aug 31 '18 at 16:25

1 Answers1

1

The problem is that there's only one Device.prototype.saveLocation function. Every time you create a new device, you're overwriting this function with the most recent one, which has the last value of self in it.

Prototype functions should not be created in the constructor, they should be defined just once. It doesn't need to use self, because it receives the object it's called on as this.

You only need to use self in callback functions that are defined in the constructor, not methods of the object or prototype.

So it should be like this.

function Device(socket) {

  this.imei = false;
  this.status = false; //maintaining the logged in status
  let self = this; //saving this variable

  this.on('data', function() { //Event on the device object

    //I want to access self.imei

  });
}

Device.prototype.saveLocation = function(parts) {
  //Here the value of self changes to the value of self of the recent object created
  console.log("In save location : IMEI " + this.imei);
};

You can also define the callback function using an arrow function, then it inherits this from where it was defined.

function Device(socket) {

  this.imei = false;
  this.status = false; //maintaining the logged in status
  let self = this; //saving this variable

  this.on('data', () => { //Event on the device object

    //You can access this.imei here

  });
}

Device.prototype.saveLocation = function(parts) {
  //Here the value of self changes to the value of self of the recent object created
  console.log("In save location : IMEI " + this.imei);
};
Barmar
  • 741,623
  • 53
  • 500
  • 612
  • My question basically revolves around the use of self by many developers. In the 'data event' on the object, if I want to access the this variable, I can save that first in the self variable but as you said that gets overwritten, so how can I achieve the same without using bind() or any other method? – Abhishek Yadav Aug 31 '18 at 16:32
  • No, that doesn't happen in the data event listener, because each object gets a different one. The problem is only with the prototype, because they're shared by all the objects. – Barmar Aug 31 '18 at 16:33
  • You could also use `this.saveLocation = function ...` and then you could use `self.imei`. But there's no need, because methods get `this`. – Barmar Aug 31 '18 at 16:37
  • https://stackoverflow.com/questions/20279484/how-to-access-the-correct-this-inside-a-callback In the 'Don't use this' section, the author used a self variable for the event listener, by the logic that should result in the same problem shouldn't it? – Abhishek Yadav Aug 31 '18 at 16:37
  • 1
    No, it doesn't result in the same problem, because each object gets its own event listener, and that listener is created in the scope of `self` when the object was created. When you create another object, it doesn't do anything to the listener that was added to the previous object. – Barmar Aug 31 '18 at 16:40
  • 1
    Every object has its own set of listeners, but there's only one `Device.prototype` that's shared by all `Device` objects. – Barmar Aug 31 '18 at 16:41
  • I just had this last question, that is it actually linked to closures in the case of Device.prototype? Maybe the declaration here always access the same self variable and all the subsequent objects change the same self variable because they are run only once? And in the case of event listeners, every new object has new self variable in it's closure? – Abhishek Yadav Aug 31 '18 at 16:45
  • `Device.prototype` shouldn't be a closure, it should be defined outside the constructor function. If you define it inside the constructor, it gets redefined every time you create a new object. It's like a global variable. – Barmar Aug 31 '18 at 16:51
  • 1
    Each event listener is independent, because you use `this.on` and it attaches the listener to the current object. And the function is a closure, so it saves the current `self` variable. – Barmar Aug 31 '18 at 16:52
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/179198/discussion-between-abhishek-yadav-and-barmar). – Abhishek Yadav Aug 31 '18 at 16:52