The topic “this” in JS is SIMPLE as a rock is currently the subject of lively discussion — readers and analysts are keeping a close eye on developments.
This is taking place in a dynamic environment: companies’ decisions and competitors’ reactions can quickly change the picture.
What if I tell you that there is no magic and you can come up with it in a few minutes?
What if I tell you that there are simple 5-step algorithms that will help you quickly and definitively solve any this-related task in JS and feel confident when working with it?
When you define a function, you define which parameters it must expect. You define explicit parameters. for example, explicit parameter smth in function logSmth(smth) {console.log(smth)}.
this is very same to it, but it is an implicit parameter. It means that the engine passes it itself, even though you don’t declare it.
In case with explicit parameters You decide what to pass, and in case with implicit parameters (including this) the Engine decides itself, ruling by its own rules STEP BY STEP.
To decide what to pass inside your function under this value JS engine uses 5 simple conditions, 5 simple questions, step by step:
If your function is arrow one, then the engine does not pass this at all, and when you try to access this from within an arrow function, then the engine looks for it through closure, same as any other variable.
If you try to access this from within an arrow function, then it does not matter whether it is called as a method, whether strict mode is enabled, or even if the function was modified by .bind. If you try to access this from within an arrow function, then the engine will always look for it through the function’s closure, same as a plain variable.
You can’t explicitly specify the value of this during the creation of the function. But you can create a new, modified one using .bind with an explicitly specified value of this, or you can call a function using .call or .apply, also explicitly specifying what to use as this.
So if you try to access this from within a normal (not arrow) function and you modified it by .bind , .call, or .apply, then this will be exactly what you have specified.
If you try to access this from within a normal function that was not modified by .bind and your function IS called as a constructor right after new (for example, new User()), then inside this will be that newly created object.

If you try to access this from within a normal function that was not modified by you and your function is NOT called as a constructor after new, but IS called as an object’s method (after a dot), then this will be the object before the dot.
And that function is NOT called as a constructor after new and is NOT called as an object’s method.
The final decision that the engine will make depends on whether “use strict” is enabled.
If “use strict” is enabled, then the engine will pass undefined as the value of this, and if “use strict” is not enabled, then the engine will pass the global object (window) as the value of this.
Explanation of example 1.1. In both cases, we have normal, not an arrow function. In both cases, those functions don’t have the “pinned” value of this explicitly. In both cases, functions are called as plain functions, not as constructors or methods. And in both cases, there are sloppy, not strict modes. So in both cases you will see window in the console.
Explanation of example 1.2. We have normal, not an arrow function. That function doesn’t have the “pinned” value of this explicitly. The function is called a plain function, not a constructor or method. Regardless of whether it was wrapped with another function, that has no sense and impacts on nothing. And of course you see window in the console.
Explanation of example 1.3. In both cases, we have normal, not an arrow function. In both cases, those functions don’t have the “pinned” value of this explicitly. In both cases, functions are called as plain functions, not as constructors or methods.
And because we have strict mode enabled, this is undefined, not window.
Explanation of example 1.4. In both cases, we have normal, not an arrow function. In both cases, those functions don’t have the “pinned” value of this explicitly. In both cases, functions are called as plain functions, not as constructors or methods.
But the code of the first function runs in sloppy mode, and the code of the second function runs in strict mode.
Explanation of example 2.1. Function is not an arrow, but normal. Not .bind, not .call/.apply was not used. The function was not called as a constructor after new, but it was called as a method. And console.log(this) will log that object. And console.log(this === object) will be true.
Explanation of example 2.2. Functions are not arrow, but normal. Not .bind, not .call/.apply was not used. But as functions are called after the keyword new (it means as constructors), then the value of this is that object.
Explanation of example 2.3. Function is not an arrow, but normal. Not .bind, not .call/.apply was not used.
Even though we declared the function starting with a capital letter and planned to use it as a constructor, we didn’t use it as a constructor. We move that function inside the object and call it as the object’s method. And then during the first function’s call, this was that object, and the function replaced modifyAndLogThis with 67 . And then during the second call object.modifyAndLogThis was 67, and 67 is a number, not a function, so you see an error in the console.

Explanation of example 2.4. Function is not an arrow, but normal. Not .bind, not .call/.apply was not used.
Even though we declared the function starting with a capital letter and planned to use it as a constructor, we didn’t use it as a constructor. We called them as plain separate functions.
Errors in two places (where I commented code) will be because it is forbidden to use constructors in that way.
And results and reasons in other places I think are obvious.
Explanation of example 4.1. Functions are arrow. Again. Functions are arrow. So it .bind/.call/.apply don’t matter. Whether they are methods or not doesn’t matter. Whether they are constructors matters because we can’t use an arrow function as a constructor, but anyway. And whether there is sloppy mode or strict mode, more so doesn’t matter.
Really matters that they are arrow functions and the engine will look for this within the closure same as for any other variable.
Explanation of example 4.2. In both cases, there will be errors. In the first case, because an arrow function can’t be a constructor. And in the second case, there is a syntax error.
Explanation of example 4.3. Here you must pay really huge attention! arrowFunction1 is an arrow one, and arrowFunction2 is an arrow one. And of course, in both cases, the engine looks for the value of this within the closure, just as it looks for randomNumber. But those functions have different closures. That is why the values of this and of randomNumber are different.
Templates let you quickly answer FAQs or store snippets for re-use.
Are you sure you want to hide this comment? It will become hidden in your post, but will still be visible via the comment’s permalink.
For further actions, you may consider blocking this person and/or reporting abuse
Thank you to our Diamond Sponsors for supporting the DEV Community
Google AI is the official AI Model and Platform Partner of DEV
DEV Community — A space to discuss and keep up software development and manage your software career
Built on Forem — the open source software that powers DEV and other inclusive communities.
We’re a place where coders share, stay up-to-date and grow their careers.
