Reputation: 720
I have the following code that should display an incrementing number once a second:
let timer_demo = {
count: 0,
timer: null,
update: function() {
this.count++;
console.log(this.count);
this.timer = setTimeout(this.update, 1000);
}
};
timer_demo.update();
However, when I run this in Chrome I get a "1", then a "NaN" a second later and then nothing. The timer stops. I get the feeling the problem is that I'm not understanding what is going on with "this" in this context. I just don't know what it is. The fact that the second time the "update()" method gets invoked, the "count" field is "NaN" would seem to support this assertion. Can anybody shed some light on this for me?
Thanks!
Upvotes: 1
Views: 75
Reputation: 1381
In your object the update
property only has a reference the to function, your object
doesn't owns it in any way. The function itself is like a free agent nobody can own it.
For your issue either use bind
as suggested by other answers or use arrow function inside the setTimeout
let timer_demo = {
count: 0,
timer: null,
update: function() {
this.count++;
console.log(this.count);
this.timer = setTimeout(() => {
this.update()
}, 1000);
}
};
timer_demo.update();
For a more in-depth guide on this
assignment you can read this article.
Upvotes: 0
Reputation: 121
var timer_demo = {
count: 0,
timer: null,
update: function() {
console.log(this);
this.count++;
console.log(this.count);
this.timer = setTimeout(this.update.bind(this), 1000);
}
};
timer_demo.update();
In setTimeout callback this is window object by default (in non strict mode). To pass custom this to setTimeout callback, bind is used.
For better understanding of this in javascript, read http://javascriptissexy.com/understand-javascripts-this-with-clarity-and-master-it/ .
Upvotes: 0
Reputation: 2880
You can use the new arrow functions to deal with this. They don't bind their own this
, so you'll end up getting it from outside environment.
let timer_demo = {
count: 0,
timer: null,
update: () => {
this.count++;
console.log(this.count);
this.timer = setTimeout(this.update, 1000);
}
};
timer_demo.update();
Upvotes: -1
Reputation: 2731
The function setTimeout doesn't call this.update, but rather takes a copy of the update function and repeats it. Unfortunately it loses its bind to the original "this".
To work around it, you can do the following:
let timer_demo = {
count: 0,
timer: null,
update: function() {
this.count++;
console.log(this.count);
this.timer = setTimeout(this.update.bind(this), 1000);
}
};
timer_demo.update();
This makes sure that the function copy is bound to this.
Upvotes: 3