In function functions, this is not determined by lexical scope.
It’s determined by how the function is called, and in what context.
Each function function creates its own this binding environment.
function f(){
this; // This `this` is distinct …
function g(){
this; // … from this `this`.
}
}
function f(){
console.log(this);
}
const objX = {
f
},
objY = {};
objX.f(); // Logs `objX`, because the expression `objX.f` is a member of a reference.
f(); // No `this` binding. `f` by itself isn’t the member of a reference.
f.call(objY); // Logs `objY`, because `this` was explicitly set.
Arrow functions, on the other hand, get the this binding from their lexical scope.
Arrow functions do not create their own this binding environment.
function f(){
this; // This `this` is the same …
() => {
this; // … as this `this`.
};
}
You’re calling f6 with .call to provide a this binding.
That’s where the f6 function gets its this value from, but f6 doesn’t use its this value.
Unrelatedly, f6 returns a function that happens to use this.
Again, it’s a function function, so its this binding depends on the call.
If you’re wondering what the returned function’s this value will be, you’ll have to examine the call:
f6.call(obj)();
// Equivalent to:
(f6.call(obj)) ();
// -^^^^^^^^^^^^- Returned function.
// ^^ Call.
.call or .apply isn’t used on the returned function, and .bind wasn’t used, so the this binding isn’t set explicitly.
(f6.call(obj)) also isn’t an expression with a member of a reference (i.e. a MemberExpression).
The call was performed without providing a context, so the context will be globalThis, or undefined in strict mode.
Using an arrow function resolves this:
function f6(){
return () => console.log(this);
}
f6.call(obj)(); // Logs `obj`.
Alternatively, using .bind in the return would also resolve this:
function f6(){
return function(){
console.log(this);
}.bind(this);
}
f6.call(obj)(); // Logs `obj`.
And of course, using something that is lexically scoped1, i.e. variables, would also resolve this:
function f6(){
const that = this;
return function(){
console.log(that);
};
}
f6.call(obj)(); // Logs `obj`.
1: I guess you could say that this is also lexically scoped, but is overshadowed by each nested function function.
See also: