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: