Losing this when calling an object's method

Hello everyone! I’d like to ask something about losing this when calling an object’s method. I understand that this is evaluated at running time (this = the object -aka context- that called the function) and we cannot change that (unless we use an explicit binding, like bind, call or apply). I understand, also, that arrow functions have no this, which is always taken from the outer scope (in pseudo code we could say: find out where the function/method we’re calling was defined, and use that context as this)… Yet, I’m a bit confused about this snippet of code:

let user = {
  firstName: "John",
  sayHi() {
    alert(`Hello, ${this.firstName}!`);
  }
};

setTimeout(user.sayHi, 1000); // Hello, undefined!
//While: 

setTimeout(function() {
  user.sayHi(); // Hello, John!
}, 1000);

//And with arrow function:

setTimeout(() => user.sayHi(), 1000); // Hello, John!

//To understand it better, I can picture it this way
let func = user.sayHi; //I assign to a variable a reference to the  user's *sayHi* method
console.log(func) //[Function: sayHi]
func(); /* TypeError: this is undefined; 
*/

That’s because I got just the function (sayHi), as I’d cut it from the object, right? So when I call it the function (obviously) tries to retrieve the value of this, but there is not context, no object calling it at all, right? Or it’s because the context is considered the window object, where we don’t have a firstName property? (It’d work anyway in strict-mode, even with a variable firstName in the global scope)

//This, in non-strict, this snippet works: 

name = 'Jack';
function test(){
 console.log(this.name)
}
test() //Jack

What happens with the setTimeout snippet, exactly? If I’m not wrong, setTimeout uses the window object by default, so setTimeout(user.sayHi, 1000) is like saying ‘get the property firstName from the global scope’, where obviously we don’t have one. Why, then, a wrapper like setTimeout(function() { user.sayHi(); // Hello, John! }, 1000); works? I’m really confused, could someone help me in figuring that out please?

Is the question why you’re getting “Hello, undefined!” in your first case, it’s because you are using sayHi as a callback function, which changes its context.

Here is an article on registering methods as callbacks:

And here is a pretty good StackOverflow that dives into it:

I’m reading the articles you shared, thank you. My question, rather than why I got undefined is: why passing the method to a wrapper function works?

setTimeout(object.method, 1000) //doesn't work
setTimeout(function(){object.method}) //works

@ArielLeslie
Hey Ariel, it took some time and I’ve read carefully the articles you’ve attached, as well as the MDN documentation on this keyword and closure.

I understand the logic behind this:

function outer(x){
    return function(){
        return ++x
    }
}

let counter = outer(5);
counter(), // 6
counter(), // 7
counter() // 8

(A closure has access to all the properties/variables of the lexical environment where it was defined; as long as a function/object can be referred, it won’t be deleted by the garbage collection)
Or the logic behind this:

function foo(){
    console.log(this.a)
}
let obj = {
    a: 22,
    foo: foo
}

let anotherObj = {
    a: 11,
    foo: foo.bind(obj)
}

obj.foo()//22
anotherObj.foo()// ! 22 

What I’d like to figure out, if possible, is the mechanism that allows an anonymous function to retrieve the correct value of themphasized textis. Specifically, how is it that the anonymous function, when passed as a callback, can correctly remember the value of this? I mean, as I said I kind of get the fact that a closure remembers the properties/variables inside the lexical scope where they were defined. This look fine to me:

function A(){
//lexical environment of A
// variables, arguments etc...
function B(){
//lexical environment of B, which has access to the lexical environment of A
}
}

But this?..

//at the moment of calling
callRandomFunction(
//lexical environment of the function call
innerAnonymousFunction(){
//has access to outer lexical environment
}
)

What happens here? I have two ideas:

  1. At the moment of the call, the arguments passed are retrieved and the anonymous function, being in the scope of the outer function, remembers them and can access them correctly, at any moment (as if, for example, it stored the data inside arguments).
  2. Inside the anonymous function, we try to trigger the method that was passed; since we don’t find the object we’re looking for in the scope of the outer function, following the normal rule for looking up a property/variable we check the outer scope, the global, where we find it.

I’m really not getting the idea behind wrapping a method within a closure; I don’t get the logic of this particular case. I know I’ve written a very messy post, but I’m really confused and frustrated and I don’t know how to get that concept in my head… Thanks to anyone that will reply :slight_smile: