简体   繁体   中英

Scope of arrow function vs es5 function in setTimeout

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

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 .

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?

Actually its not that it is unable to access the global but the problem is that setTimeout has it's own scope so it is just overcoming the global this.

What you can do is :

let self = this;
const dog = {
  name: 'fluffy',
  type: 'dog',
  sound: 'woof!',
  makeSound: function() {
    setTimeout(() => {
      console.log("makeSound", self )
    }, 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);

I hope this will solve your problem of global scope.Hope it helps you.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM