0

I am experimenting with this and arrow functions. Ran into some trouble regarding the lexical scope of arrow function in setTimeout.

The makeSound method returns this as the dog object. Why does it not take the scope of the global object since the arrow function is inside the setTimeout method? Interestingly, the whatIsThis method returns the Timeout object and not the global object. I am confused on this as well.

const dog = {
  name: 'fluffy',
  type: 'dog',
  sound: 'woof!',
  makeSound: function() {
    setTimeout(() => {
      console.log("makeSound", this)
    }, 1000)

  },
  whatIsThis: function() {
    setTimeout(function() {
      console.log("whatisthis", this)
    }, 1000)
  }
}


dog.makeSound() // returns dog obj
dog.whatIsThis() // returns Timeout obj


setTimeout(() => {
  console.log("global", this)
}, 1000) // returns global obj
Quentin
  • 914,110
  • 126
  • 1,211
  • 1,335
aijnij
  • 91
  • 2
  • 10
  • 2
    [Answer to part 1](https://stackoverflow.com/questions/34361379/are-arrow-functions-and-functions-equivalent-exchangeable/34361380#34361380). [answer to part 2](https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/setTimeout#The_this_problem). – Raymond Chen Aug 23 '19 at 13:18
  • 1
    Are you sure dog.whatIsThis() logs the Timeout object. For me it logs the window object and it makes sense, since you declare a new lexical scope which is called by setTimeout. The arrow function takes its this from the outer lexical scope (makeSound in your case, which is equal to dog). – Valentin Aug 23 '19 at 13:28

2 Answers2

0

Why does it not take the scope of the global object since the arrow function is inside the setTimeout method?

The callback is not "inside" the setTimeout function. It is passed as argument to the setTimeout function.

Consider the following, equivalent code:

const dog = {
  name: 'fluffy',
  type: 'dog',
  sound: 'woof!',
  makeSound: function() {
    const cb = () => console.log("makeSound", this);
    setTimeout(cb, 1000)
  },
}

This code behaves exactly the same. The only difference is that the callback function is assigned to variable first before being passed to setTimeout.

This should demonstrate that the arrow function is not "inside" setTimeout, but rather inside makeSound. Arrow functions resolve this lexically, just like any other variable. So we have to find out what the value of this inside makeSound is. And in order to find that out, we have to look at how the method is called. Since it is called as dog.makeSound(), this refers to dog.

Felix Kling
  • 795,719
  • 175
  • 1,089
  • 1,143
-1

The scope the arrow function gets declared in is the scope of the function surrounding it (dog.makeSound), not the function the arrow function gets passed to.

Whe you call dog.makeSound(), this inside of the makeSound function refers to dog, thus it does so inside the arrow function too.

  // no matter what the surrounding is ...
  const that = this;
  /*no matter whats here*/(() => {
     console.log(that === this); // this will always be true
  })();

Interestingly, the whatIsThis method returns the Timeout object and not the global object. I am confused on this as well.

Me too. That behaviour is strange, are you sure that you are not missinterpreting the consoles output?

Jonas Wilms
  • 132,000
  • 20
  • 149
  • 151