0

I'm struggling with "this" keyword in JS. I've listed 3 different cases that I'm confusing with.

const person = {
    name: "joe",
    talk(){
        this.foo(function (){
            console.log(this);
        });
    },
    foo(a) {
        a()
    }
};
person.talk();

In the first scenario: despite foo is a member of person object; when I call foo function it returns me a window object reference.

const person = {
    name: "joe",
    talk(){
        foo(function (){
            console.log(this);
        });
    },

};

function foo(a){
    a()
}
person.talk();

In the second scenario: there is nothing changed, though I put foo function outside of person object.

But if I change the way of defining the callback function within foo function with Arrow notation as follows:

const person = {
    name: "joe",
    talk(){
        foo(() => {
            console.log(this);
        });
    },

};

function foo(a){
    a()
}
person.talk();

Then this time, the first scenario and the second scenario that I mentioned above print out the reference of person object regardless whether foo is defined within person object or not.

What is the basis of those results?

  • `this` in arrow function is the same `this` when you create the function – apple apple Aug 21 '20 at 15:29
  • The use of `this` in an arrow function does not cause `this` to be altered. It therefore points to whatever it did just prior to the arrow function invocation. – Scott Marcus Aug 21 '20 at 15:29
  • Does this answer your question? [How to access the correct \`this\` inside a callback?](https://stackoverflow.com/questions/20279484/how-to-access-the-correct-this-inside-a-callback) – David Aug 21 '20 at 15:46
  • I recommend checking out the [MDN `this` documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this) which does quite a good job of explaining `this`. – 3limin4t0r Aug 21 '20 at 16:31

1 Answers1

0

I'm going to shamelessly copy-paste https://www.w3schools.com/js/js_arrow_function.asp here:

In regular functions the this keyword represented the object that called the function, which could be the window, the document, a button or whatever.

With arrow functions the this keyword always represents the object that defined the arrow function.

To elaborate further on your scenarios:

Regular function

const person = {
    name: "joe",
    talk(){
        this.foo(function (){
            console.log(this);
        });
    },
    foo(a) {
        a()
    }
};
person.talk();

and

const person = {
    name: "joe",
    talk(){
        foo(function (){
            console.log(this);
        });
    },

};

function foo(a){
    a()
}
person.talk();

this == the object calling the sequence of function == window

Arrow function

const person = {
    name: "joe",
    talk(){
        this.foo(() => {
            console.log(this);
        });
    },
    foo(a) {
        a()
    }
};
person.talk();

and

const person = {
    name: "joe",
    talk(){
        foo(() => {
            console.log(this);
        });
    },

};

function foo(a){
    a()
}
person.talk();

this == the object that defines the function == person

Bonus: which one to use

Quoted from https://www.freecodecamp.org/news/when-and-why-you-should-use-es6-arrow-functions-and-when-you-shouldnt-3d851d7f0b26/:

ES6 arrow functions can’t be bound to a this keyword, so it will lexically go up a scope, and use the value of this in the scope in which it was defined.

If you are familiar with Fn.bind(), it's a known trick to change what a regular function refers to as this. An arrow function does not follow this trick and always stick to the this that refers to its parent scope.

Especially if you are developing a library for others to use, use an arrow function if you want to be confident on using this to refer to its parent scope. Use a regular function for event handling since this will refer to the event source (button, text field etc). If you must use a regular function and must refer to its parent scope, use closure to freeze the parent scope instead of using this.

Lukman
  • 18,462
  • 6
  • 56
  • 66