After more than 6 years explaining frontend to both vocational training and university students, I have found it difficult to understand the use of the reserved word “this” in JavaScript. The problematic of this reserved word has been hidden with the appearance of TypeScript and frameworks such as Angular, although under these layers there is still JavaScript, and the lack of knowledge causes errors that takes hours to fix.
Context Vs Scope
The first concepts we have to clarify is the difference between context and scope. These two terms are confused by many frontend developers (I myself took a while to understand them).
All the functions have associated scope and context. Scope defines the access to variables of a function when the function is invoked. On the other hand, Context is always the value of the reserved word this
which is a reference to the object that owns the execution of the code.
Execution Context
JavaScript is a single-threaded language, so it can just execute one task at the same time. The rest of tasks are queued in the Execution Context. Unfortunately, when they say ‘execution context’, they mean scope (why did they do that?).
In each call, a function appends its context to the execution context. So each function creates its own execution context (its own scope).
Once the call ends, the context gets destroyed and the execution context will be transfered to the parent context. There is only one global context but finite function contexts.
“this” refers to global object
By default the execution context for an execution is global, which means that if a code is being executed as part of a simple function call then “this” refers to global object. In the case that you run your code in a browser the global object is “window” object while that in node.js the global object can be the special “global” or the “module.exports”.
The following code is running in a browser.
The following code is running in a node.js environment.
“this” refers to new instance
When a function is invoked with “new” keyword then the function is known as constructor function and returns a new instance. In such cases, the value of “this” refers to newly created instance.
The new keyword performs following four tasks:
- It creates new empty object e.g. obj = { };
- It sets new empty object’s invisible ‘prototype’ property to be the constructor function’s visible and accessible ‘prototype’ property. (Every function has visible ‘prototype’ property whereas every object includes invisible ‘prototype’ property)
- It binds properties or functions which are declared with
this
keyword to the new object. - It returns a created object unless the constructor function returns a
non-primitive value (custom JavaScript object). If constructor function does not include return statement then compiler will insert ‘return this;’ implicitly at the end of the function. If the constructor function returns a primitive value then
return this;
will not be inserted.
Now that we have a new execution context new properties can be defined for Dog function, in this case we got 2 new dogs of Paw Patrol, Turbot and Rubble.
As you may know, the great advantage of Javascript is using the prototype of each function (I recommend you to read about prototype pattern which is used in other languages object oriented, due to they are not native).
“this” refers to invoker object (parent object)
In JavaScript, the object’s properties can be a function or a simple value. When a object’s method is invoked then “this” refers to the object which contains the method which is being invoked.
In the following example you can see how the this value is different depends of the execution context.
“this” with call or apply methods
A function in JavaScript is also a special type of object. Every function has call
, bind
and apply
methods. These methods can be used to set custom value of "this" to the execution context of function.
In the following code you can see how to change the execution context using the call method.
“this” with bind method
The bind
method returns a new method with "this" refers to the first argument passed.
“this” with fat arrow function
As part of ES6, there is a new way introduced to define a function; using fat arrow
(=>).
When a fat arrow is used then it doesn’t create a new value for “this”. “this” keeps on referring to the same object it is referring, outside the function. There is not a new execution context.
The following code the value of this is the function growUp
which there is not a age
attribute in its execution context.
The solution, in this case is not creates a new execution context. Therefore, we can use a fat-arrow.
“this” with fat arrow function and apply-call
When you use the apply or call methods over a fat-arrow function the this i not changed due to the fat-arrow does not own this
. Therefore, the apply and call methods only call the original method with parameters while "thisArg" is ignored.
“this” with class sugar syntax
When we use class
sugar syntax, it is common to use this
the same way as any other object oriented programming language. However, the majority of OOP languages do not allow defining functions within functions.
Therefore, if we have a look at the following code, there is a method
displayName
which includes a method called innerDisplay
which uses the
keyword this
. If we execute innerDisplay
function in this context we will be creating a new execution context so this
value will not belong to Dog
class. Nevertheless, in order to solve this issue we can use any of the tricks explained along this blog. In this case, we will use apply
function to change the context of innerDisplay
function to Dog
's context.
More, More, More…
- https://www.tutorialsteacher.com/javascript/new-keyword-in-javascript
- https://medium.com/quick-code/understanding-the-this-keyword-in-javascript-cb76d4c7c5e8
- https://javascriptissexy.com/understand-javascripts-this-with-clarity-and-master-it/
- http://ryanmorr.com/understanding-scope-and-context-in-javascript/
- https://medium.com/@marjanrab/javascript-scope-context-and-this-under-the-hood-43c32033c9f9
- https://scotch.io/tutorials/understanding-scope-in-javascript
- https://medium.com/javascript-in-plain-english/hello-javascript-this-bb97c54f0823
*Originally published at https://www.carloscaballero.io on May 17, 2019.
Top comments (2)
"It sets new empty object’s invisible ‘prototype’ property"
I guess it should be --proto-- ,I put dashes instead of underscores, instead here. And as for now we can access it and see it if console.log the object
God, I didn't know that I could use
this
to refer to the global context. This is surprising.