Referencing in Javascript

I wrote the following code in Javascript and it didn’t work. I was told this is because I need to make the “stop” function an arrow function or change the following line
console.log("Stopwatch re-started from", (d.getTime() - this.watchtime) / 1000)

to

console.log("Stopwatch re-started from", (d.getTime() - me.watchtime) / 1000)

and in the outer scope of the function say

me=this

I don’t understand why this fixes the issue. Please can someone explain?

I didn’t have to use arrow functions (or the me expression) in the “start” function btw!

function StopWatch() {
  this.watchtime = 0;
  this.started = 0;
  this.start = function() {
    if (this.started) {
      d = new Date()
      console.log("Cannot start watch twice. Current time is", (d.getTime() - this.watchtime) / 1000)
    } else if (this.watchtime == 0) {
      this.started = 1
      d = new Date()
      this.watchtime = d.getTime()
    } else {
      d = new Date()
      console.log("Stopwatch re-started from", (d.getTime() - this.watchtime) / 1000)
      this.watchtime = d.getTime() - this.watchtime
      this.started = 1
    }
  }
  this.stop = function() {
    if (this.started == 0) {
      console.log("Stopwatch has not yet been started")
    } else {
      d = new Date()
      this.total_time = (d.getTime() - this.watchtime) / 1000
      console.log("Stopped at:", this.total_time)
      this.started = 0
    }
  }
}
sw = new StopWatch
sw.start()
setTimeout(sw.stop, 3000)

I assume by “not work” you mean that it returns NaN? The little I tested, the methods seemed to work on their own, but setTimeout is causing the issue. Is this not the case? Or maybe I missed something.

setTimeout: The “this” problem

setTimeout( () => {sw.stop()}, 3000)

1 Like

You have to understand how this works in JS in order to understand why your code works the way it does. When calling a setTimeout function you are passing a reference to your method sw.stop as one of the arguments, as a callback. This is a bad idea, because it gets called as a function on an object Timeout, not as a function on an object StopWatch, the way you are expecting it to. Just console.log(this) inside of your stop method to understand what i’m talking about.

One solution to get around this problem is to not pass methods as callbacks to your setTimeout function. But if you wanna do it this way you can change the value of this when passing the function reference to setTimeout using bind:

setTimeout(sw.stop.bind(sw), 3000);

Another solution that might help you understand ‘this’ keyword better would be to wrap your method call in a function, this will produce the following result:

function func() {
  console.log(this); // = Timeout {} object , we are calling func on Timeout object right now
  sw.stop(); // if you call stop method here this will be set to your StopWatch {} object
}

setTimeout(func, 3000);

And your stop method will work the way you expect it to. Same as func solution, but with cleaner code - using an anonymous function:

setTimeout(() => { sw.stop() }, 3000);
1 Like

Thank you so much for explaining this. Why then does “me” or an arrow function fix this and why is it still possible to use “this” throughout the rest of the function

This is working code but still uses “this”

function StopWatch() {
  this.watchtime = 0;
  this.started = 0;
  this.start = () => {
    if (this.started) {
      d = new Date()
      console.log("Cannot start watch twice. Current time is", (d.getTime() - this.watchtime) / 1000)
    } else if (this.watchtime == 0) {
      this.started = 1
      d = new Date()
      this.watchtime = d.getTime()
    } else {
      d = new Date()
      console.log("Stopwatch re-started from", (d.getTime() - this.watchtime) / 1000)
      this.watchtime = d.getTime() - this.watchtime
      this.started = 1
    }
  }
  this.stop = () => {
    if (this.started == 0) {
      console.log("Stopwatch has not yet been started")
    } else {
      d = new Date()
      this.total_time = (d.getTime() - this.watchtime) / 1000
      console.log("Stopped at:", this.total_time)
      this.started = 0
    }
  }
}
sw = new StopWatch
sw.start()
setTimeout(sw.stop, 3000)

and this uses “me” in once instance and “this” in the others

function StopWatch(){
    var me = this;
    this.watchtime = 0;
    this.started = 0;
    this.start = function(){
        if(this.started){
            d = new Date()
            console.log("Cannot start watch twice. Current time is", (d.getTime() - this.watchtime)/1000)
        }else if(this.watchtime == 0){
            this.started = 1
            d = new Date()
            this.watchtime = d.getTime()
        }
        else{
            d = new Date()
            console.log("Stopwatch re-started from", (d.getTime() - this.watchtime)/1000)
            this.watchtime = d.getTime() - this.watchtime
            this.started = 1
        }
    }
    this.stop = function(){
        if (this.started == 0){
            console.log("Stopwatch has not yet been started")
        }else{
            d = new Date()
            this.total_time = (d.getTime() - me.watchtime)/1000
            console.log("Stopped at:", this.total_time)
            this.started = 0
        }
    }
}
sw = new StopWatch;
sw.start();
setTimeout(sw.stop, 3000);

In the first example, it’s because arrow functions do not have their own bindings to the this.

No separate this

An arrow function does not have its own this . The this value of the enclosing lexical scope is used; arrow functions follow the normal variable lookup rules. So while searching for this which is not present in current scope they end up finding this from its enclosing scope.

Second example. You are making a local variable to hold the this context.

stackoverflow

self is being used to maintain a reference to the original this even as the context is changing. It’s a technique often used in event handlers (especially in closures).

Links galore




2 Likes

Thank you for explaning this to me :slight_smile:

You seem to misunderstand the purpose of your StopWatch() function. It’s a constructor, a constructor gets called once when you are creating an object with a new keyword. When you are adding a ‘me’ variable (also sometimes called a field) to your object you are saving a reference to this in it, which during an object creation using a constructor always points to the object that is currently being created. Hope this makes sense.

As for as “why is it still possible to use “this” throughout the rest of the function” you should really brush up on your basics of OOP in JS and working with objects. Don’t stick to FCC curriculum in your education, branch out, learn from different sources.

1 Like