Arcadio Alivio Sincero
Arcadio Alivio Sincero

Reputation: 720

I think I'm misunderstanding "this" in JavaScript

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

Answers (4)

spark
spark

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

NishiJain
NishiJain

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

spanky
spanky

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

MiltoxBeyond
MiltoxBeyond

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

Related Questions