Meaning of enclosing lexical context when we use arrow function (Lexical this)

Viewed 748

I have a question about this in javascript.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this

When I read this article, it said

In arrow functions, this retains the value of the enclosing lexical context's this. In global code, it will be set to the global object

But for example, the code below

const person = {
  hobby: "loafing around",
  sayHobby: function() {
    setTimeout(() => {
      console.log(`My hobby is ${this.hobby}`);
    }, 100);
  }
};

person.sayHobby()

In this example, Arrow function callback in setTimeout was enclosed by setTimeout function. so I think this it should be global(window) because setTimeout is defined in gloabal object.

I know my thinking is wrong, but don't know how to understand the meaning of enclosing lexical context. Could you please help me to understand this ? How to find lexical context ?

1 Answers

In the global scope this points to global object (in a browser it will be window). Now when you call person.sayHobby(), sayHobby is NOT an arrow function. So this call create a new lexical context where this points to whatever to the left of the . in person.sayHobby() which is the person object.

Next you call setTimeout which is equivalent to window.setTimeout. The setTimeout call will have lexical scope where this evaluates to window. But we don't see this because setTimeout is an internal browser method. You can't see it's code.

When you call setTimeout you pass a function argument. That argument included the lexical context of the caller. So then setTimeout calls your arrow function back, it calls it with the lexical context passed in it.

// global context
// this evaluates to window. This should output true
console.log('this here evaluates to window: ' + (window === this));
const person = {
  hobby: "loafing around",
  sayHobby: function() {
    // This is a non arrow function. It creates a new lexical context
    // This should also print true
    console.log('this evaluates to the person object used for the call: ' + (this.hobby === 'loafing around'));
    // setTimeout is called without this
    // Any call without this. preceding it assumes that the function is in global object.
    // So this is the same as window.setTimeout
    setTimeout(() => {
      // This is an arrow function. No new scope is created.
      // This should print true 
      console.log('this evaluates to the person object used for the sayHobby call: ' + (this.hobby === 'loafing around'));
      console.log(`My hobby is ${this.hobby}`);
    }, 100);
  }
};

// Calling person.sayHobby will make this evaluate to person inside the sayHobby() call
person.sayHobby();

Now let's change the code and have a global function defined in the globalScope

// 
function myGlobalFunction(callback) {
    console.log('inside myGlobalFunction this evaluates to window: ' + (window === this));
  callback();
}
// global context
// this evaluates to window. This should output true
console.log('this here evaluates to window: ' + (window === this));
const person = {
  hobby: "loafing around",
  sayHobby: function() {
    // This is a non arrow function. It creates a new lexical context
    // This should also print true
    console.log('this evaluates to the person object used for the call: ' + (this.hobby === 'loafing around'));
    // setTimeout is called without this
    // Any call without this. preceding it assumes that the function is in global object.
    // So this is the same as window.setTimeout
    myGlobalFunction(() => {
      // This is an arrow function. No new scope is created.
      // This should print true 
      console.log('this evaluates to the person object used for the sayHobby call: ' + (this.hobby === 'loafing around'));
      console.log(`My hobby is ${this.hobby}`);
    }, 100);
  }
};

// Calling person.sayHobby will make this evaluate to person inside the sayHobby() call
person.sayHobby();

This is basically the same. Inside myGlobalFunction the global context is has this pointing to window. But the callback argument includes the context of the caller. So then callback() is executed has person as the context.

Related