Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.javascript > #32412 > unrolled thread

ES6 class properties are undefined ?

Started byUne Bévue <unbewusst.sein@fai.invalid>
First post2017-01-29 10:18 +0100
Last post2017-01-29 15:56 +0100
Articles 7 — 3 participants

Back to article view | Back to comp.lang.javascript


Contents

  ES6 class properties are undefined ? Une Bévue <unbewusst.sein@fai.invalid> - 2017-01-29 10:18 +0100
    Re: ES6 class properties are undefined ? Martin Honnen <martin.honnen@gmx.de> - 2017-01-29 12:01 +0100
      Re: ES6 class properties are undefined ? Une Bévue <unbewusst.sein@fai.invalid> - 2017-01-29 12:14 +0100
        Re: ES6 class properties are undefined ? Martin Honnen <martin.honnen@gmx.de> - 2017-01-29 12:55 +0100
          Re: ES6 class properties are undefined ? Une Bévue <unbewusst.sein@fai.invalid> - 2017-01-29 15:50 +0100
      Re: ES6 class properties are undefined ? Thomas 'PointedEars' Lahn <PointedEars@web.de> - 2017-01-29 14:00 +0100
        Re: ES6 class properties are undefined ? Une Bévue <unbewusst.sein@fai.invalid> - 2017-01-29 15:56 +0100

#32412 — ES6 class properties are undefined ?

FromUne Bévue <unbewusst.sein@fai.invalid>
Date2017-01-29 10:18 +0100
SubjectES6 class properties are undefined ?
Message-ID<o6kc0n$jep$1@shakotay.alphanet.ch>
I've a class like that (simplified for clarity):

let SocketService = class SocketService {
   constructor(url) {
     this.url = url;
     this.ws  = null;
     this.timerID = 0;
     this.init();
   }
   init() {
     let that = this;
     this.ws = new WebSocket(this.url);
     this.ws.onclose = function() {
       that.timerID = window.setInterval(that.init, 5000);
     };
   }
}

when I shut down the WebSocket server in order to test my script
i get : this.url = undefined; (that.url too)
only the first time init() is activated gives the correct value, why ?
it seems "this" is lost...

[toc] | [next] | [standalone]


#32414

FromMartin Honnen <martin.honnen@gmx.de>
Date2017-01-29 12:01 +0100
Message-ID<o6ki2m$ek5$1@news.albasani.net>
In reply to#32412
On 29.01.2017 10:18, Une Bévue wrote:
> I've a class like that (simplified for clarity):
>
> let SocketService = class SocketService {
>   constructor(url) {
>     this.url = url;
>     this.ws  = null;
>     this.timerID = 0;
>     this.init();
>   }
>   init() {
>     let that = this;
>     this.ws = new WebSocket(this.url);
>     this.ws.onclose = function() {
>       that.timerID = window.setInterval(that.init, 5000);
>     };
>   }
> }
>
> when I shut down the WebSocket server in order to test my script
> i get : this.url = undefined; (that.url too)
> only the first time init() is activated gives the correct value, why ?
> it seems "this" is lost...

Try whether using
   that.timerID = window.setInterval(function() { that.init(); }, 5000);
instead of
   that.timerID = window.setInterval(that.init, 5000);
improves things.

[toc] | [prev] | [next] | [standalone]


#32415

FromUne Bévue <unbewusst.sein@fai.invalid>
Date2017-01-29 12:14 +0100
Message-ID<o6kiqf$vbn$1@shakotay.alphanet.ch>
In reply to#32414
Le 29/01/2017 à 12:01, Martin Honnen a écrit :
> Try whether using
>   that.timerID = window.setInterval(function() { that.init(); }, 5000);

Fine, thanks, that works !

Do you have an explanation ?

[toc] | [prev] | [next] | [standalone]


#32416

FromMartin Honnen <martin.honnen@gmx.de>
Date2017-01-29 12:55 +0100
Message-ID<o6kl8c$cro$1@news.albasani.net>
In reply to#32415
On 29.01.2017 12:14, Une Bévue wrote:
> Le 29/01/2017 à 12:01, Martin Honnen a écrit :
>> Try whether using
>>   that.timerID = window.setInterval(function() { that.init(); }, 5000);
>
> Fine, thanks, that works !
>
> Do you have an explanation ?

Your attempt with
   that.timerID = window.setInterval(that.init, 5000);
passes the function reference the expression `that.init` gives to 
setInterval, it is then executed later in the context of the window 
object and not of the SocketService instance you want it to be called 
on. My suggestion passes a function reference forming a closure on the 
`that` variable and that way setInterval calls the method on the 
intended instance and not on the window object.

[toc] | [prev] | [next] | [standalone]


#32418

FromUne Bévue <unbewusst.sein@fai.invalid>
Date2017-01-29 15:50 +0100
Message-ID<o6kvgg$mpv$1@shakotay.alphanet.ch>
In reply to#32416
Le 29/01/2017 à 12:55, Martin Honnen a écrit :
>
> Your attempt with
>   that.timerID = window.setInterval(that.init, 5000);
> passes the function reference the expression `that.init` gives to
> setInterval, it is then executed later in the context of the window
> object and not of the SocketService instance you want it to be called
> on. My suggestion passes a function reference forming a closure on the
> `that` variable and that way setInterval calls the method on the
> intended instance and not on the window object.

OK, thanks, crystal clear.

[toc] | [prev] | [next] | [standalone]


#32417

FromThomas 'PointedEars' Lahn <PointedEars@web.de>
Date2017-01-29 14:00 +0100
Message-ID<1771785.oMNUckLgyt@PointedEars.de>
In reply to#32414
Martin Honnen wrote:

> On 29.01.2017 10:18, Une Bévue wrote:
>> let SocketService = class SocketService {
       ^^^^^^^^^^^^^         ^^^^^^^^^^^^^
DRY.

>>   constructor(url) {
>>     this.url = url;
>>     this.ws  = null;
>>     this.timerID = 0;

Consider

  Object.assign(this, {
    url: url,
    ws: null,
    timerID: 0
  });

>>     this.init();
>>   }
>>   init() {
>>     let that = this;
>>     this.ws = new WebSocket(this.url);
>>     this.ws.onclose = function() {
>>       that.timerID = window.setInterval(that.init, 5000);
>>     };
>>   }
>> }
>>
>> when I shut down the WebSocket server in order to test my script
>> i get : this.url = undefined; (that.url too)
>> only the first time init() is activated gives the correct value, why ?
>> it seems "this" is lost...
> 
> Try whether using
>    that.timerID = window.setInterval(function() { that.init(); }, 5000);
> instead of
>    that.timerID = window.setInterval(that.init, 5000);
> improves things.

Things can be improved more (i.e. more efficient) if the function is not 
created every time that the event listener is called:

  var init = function () { that.init(); };

  this.ws.onclose = function () {
    that.timerID = window.setInterval(init, 5000);
  };

Or, given that ES6 is already being used,

  var init = this.init.bind(this);

  this.ws.onclose = (function () {
    this.timerID = window.setInterval(init, 5000);
  }).bind(this);

so that the “that” variable becomes unnecessary.  [However, this comes at 
the price of flexibility: with .bind() for the event listener, “this” can no 
longer be used in it to refer to the object that fired the event.  So one 
might only want to use the first .bind() here.]

But in fact, this code does not make sense.  ISTM that the 
window.setInterval() should be window.setTimeout(); at least there should be 
a window.clearInterval() in .init() for the window.setInterval() in the 
event listener.  Otherwise whenever the WebSocket instance fires a “close” 
event, new "intervals" will pile up.

-- 
PointedEars
FAQ: <http://PointedEars.de/faq> | <http://PointedEars.de/es-matrix>
<https://github.com/PointedEars> | <http://PointedEars.de/wsvn/>
Twitter: @PointedEars2 | Please do not cc me./Bitte keine Kopien per E-Mail.

[toc] | [prev] | [next] | [standalone]


#32419

FromUne Bévue <unbewusst.sein@fai.invalid>
Date2017-01-29 15:56 +0100
Message-ID<o6kvqd$n1c$1@shakotay.alphanet.ch>
In reply to#32417
Le 29/01/2017 à 14:00, Thomas 'PointedEars' Lahn a écrit :
> Martin Honnen wrote:
>
>> On 29.01.2017 10:18, Une Bévue wrote:
>>> let SocketService = class SocketService {
>        ^^^^^^^^^^^^^         ^^^^^^^^^^^^^
> DRY.

I thought "let SocketService = ..." is necessary because the file ends 
with :
export default SocketService;

i didn't mention that point.


> Or, given that ES6 is already being used,

Yes, I'm using ES6 here (for the first time).

>   var init = this.init.bind(this);
>
>   this.ws.onclose = (function () {
>     this.timerID = window.setInterval(init, 5000);
>   }).bind(this);
>
> so that the “that” variable becomes unnecessary.  [However, this comes at
> the price of flexibility: with .bind() for the event listener, “this” can no
> longer be used in it to refer to the object that fired the event.  So one
> might only want to use the first .bind() here.]

OK.

> But in fact, this code does not make sense.  ISTM that the
> window.setInterval() should be window.setTimeout(); at least there should be
> a window.clearInterval() in .init() for the window.setInterval() in the
> event listener.  Otherwise whenever the WebSocket instance fires a “close”
> event, new "intervals" will pile up.

There is a clearInterval :
     this.ws.onopen = function(message) {
       let i = 0;
       let c = that.preConnectionRequests.length;
       if (!that.timerID || that.timerID > 0) {
         window.clearInterval(that.timerID);
         that.timerID = 0;
       }

again, not metionned at first post.

Thanks !

[toc] | [prev] | [standalone]


Back to top | Article view | comp.lang.javascript


csiph-web