JavaScript this
this is not unique to JavaScript. In other languages however, this always point sat instance of a class. On the other hand, in JavaScript, this is determined as execution context is created(๐ Execution Context). Most of the execution context, with one exception of global execution context, is created on function call. The same this can refer to different things, depending on how the function is called. This makes this in JavaScript problematic.
JavaScript's this binding can be categorized into 5 patterns:
- On global code execution,
thisrefers to global object in browser andmodule.exportsin node.js. - On method invocation,
thisreferences the object that owns the method, which comes before property accessor(dot (.) or ([])). - On free function call,
thisdesignates a global object. - When a function is invoked as a constructor, with
newkeyword,thisrefers to the object created by the function. - Inside a callback function, what
thismeans is determined by the function to which the callback was passed. If not specified,thisrefers to global object by default. - On indirect invocation inside
apply(),bind(), which areFunction's prototype methods, you can designatethisbinding explicitly by passingthisobject as the first argument.
Global Code Execution
In browser, global object refers to global object window. Properties defined on this object is added to window as well.

In node.js, this in global execution context is bound to module.exports. module.exports is a built-in object that represents current file as a module. Whatever is assigned to module.exports object is exposed as a module.
It seems asymmetrical that node.js's global execution context does not bind this to global object global, an equivalent to browser's window object. Indeed, node.js this does point at global object, but in global execution context but in function execution context. We'll go over this soon.
Method Invocation
When a function is called as a method of an object, this inside the function refers to the object that called the method.
The same goes for both browser and node.js environment.
Free Function Call
When a function is called as a free function, namely not as a method of an object, this in the function again refers to global object.
In browser environment, it's global window object,
and global in node.js.
Take the following code, for example.
Even though drive function is inside the car object, this only points to car when car calls it(car.drive()). When called as a free function(freeDrive()), without property accessor, this refers to global object. It is designed as if JavaScript regards freeDrive() is invoked as a method of global object(window.freeDrive()). To enhance understanding, ย take the following code where function declaration in global code is added to window object as its property.

Sometimes, however, that free function invocation always binds this to global object is not very instinctive. Often we expect this to point to geologically proximate, just like how 'this' does in natural language.
For example, in this code:
const car = {
model: "Hyundai",
speed: 4,
drive: function (distance) {
function getTime(distance) {
// console.log(this.speed) // undefined
return distance / this.speed;
}
console.log(`It takes ${this.model} ${getTime(distance)}h to get there`);
}
};
car.drive(4); // โ It takes Hyundai NaNh to get theregetTime() fails to read this.time because getTime() is called as a free function, even though it's inside the car object.
To prevent a function from binding this to global object, one might consider using arrow function. When arrow function's ย execution skips this binding. As a result, arrow function doesn't have its "own" this. When referenced, this is borrowed from the execution context of the nearest, non-arrow function.
const car = {
model: "Hyundai",
speed: 4,
drive: function (distance) {
const getTime = (distance) => distance / this.speed;
console.log(`It takes ${this.model} ${getTime(distance)}h to get there`);
}
};
car.drive(4); // ๐ข It takes Hyundai 1h to get thereNow, this inside getTime() references this of outer function drive, which is car. It successfully calculates time needed to arrive at the destination.
Before arrow function was introduced in ES6, a common pattern to circumvent the same problem was to create a variable that points to this:
const car = {
model: "Hyundai",
speed: 4,
drive: function (distance) {
var speed = this.speed;
var getTime = function (distance) {
return distance / speed;
};
console.log(`It takes ${this.model} ${getTime(distance)}h to get there`);
}
};
car.drive(4); // ๐ข It takes Hyundai 1h to get thereBy convention, names such as self, _this were often used to point to this as a whole.
Constructor Invocation
A function serves as a constructor when invoked with new keyword. Inside the constructor function, this is the object the function is going to create .
In the above code, the function implicitly creates this = {}, adds properties to it( ย this.model = model), and returns it on constructor call (For further reading, see ๐ JavaScript Prototype - Prototype Chain),
Callback
A callback function is passed as an argument to another function. As the function given the callback decides when to call the callback, a callback passes over its control to another function. Also, what this inside the callback will be is determined by the design of the caller function.
For instance, addEventListener() lets its callback inherit its own this. Since addEventListener is attached to HTMl element, ย this inside addEventListener()'s callback is whatever comes before addEventListener's property accessor.
Some JavaScript APIs let developers designate this. They take this object as arguments, along with a callback function. Consider interfaces of some of the built-in prototype methods of Array object.
Array.prototype.forEach(callback[, thisArg])
Array.prototype.map(callback[, thisArg])
Array.prototype.filter(callback[, thisArg])
...The above code breaks without this as second argument of .forEach(), since then this no longer points to HR object and therefore cannot find properties such as employees.
If no this is passed as arguments or a caller's API has no specific behavior regarding this, a callback's this refers to global object by default. For example, setTimeout() doesn't have fixed rule regarding this and therefore its callback's this refers to window object.

Indirect Invocation
Using call(), apply(), bind() methods of Function.prototype, you can explicitly bind this of your choosing instead of letting it be determined by the surrounding context. They all take this as their first argument.
References
์ฝ์ด ์๋ฐ์คํฌ๋ฆฝํธ(Core JavaScript), ์ฌ๋จ, ์ . ์ํค๋ถ์ค, 2019. pp. 75-93.
Modern JavaScript Tutorial - Object methods, "this"
Zerocho, "Node์์์ this (this in Node)"