How this Works in JavaScript
One of the most weird concepts of javascript is where this
keyword is referencing to. Every function receives two addition parameters excluding declared parameter: this
and arguments
. The this
keyword is very important in javascript and let's see what it is.
Every function while executing has a reference to its current execution context called “ this
". Here execution refers to where the function is getting called and when it will be called. There are four rules for how "this" keyword gets bind. It tells how "this" keyword will get bind for functions. Let's see what are those.
1. Function Binding
Let's take an example and see how “this” gets bind.
We are trying to log the name which is present in person()
. In the non-strict mode it will default " this
" keyword to global object and in the strict mode it will default to undefined
. If the strict mode is applied within the person()
then this.name
will throw an error so it's not mandatory that always it should be applied at the program level. The same will happen in the case of IIFE as well.
'use strict'; var name = 'Micheal'; (function() { console.log(this.name); //this.name throws an error. })();
2. Method binding
When a function is stored as a property of an object it is called a method. When a method is invoked “ this
" is bound to the object(left of the dot). Let's consider an person
() example again.
We have taken a couple of objects obj1 and obj2 both have person
properties on them and also they are referencing to same person object in line 1. But when obj1.person
() is executed then " this
" keyword will reference to obj1
so we will get as "Messi" and exact same thing with obj2
. Let's consider another example for the same operation just to make sure where ever function is getting declared binding rule holds true.
See output remains the same and does not affect the behavior. obj1.person() will get “Messi”, obj2.person() will get “Ronaldo” and function binding rule will get as “Micheal”.
3. Apply Invocation Binding
What if we want to force a function to use a particular object for “ this
" binding without adding property reference on the object?
If you use .call()and .apply() it lets us to invoke a function and also lets us to choose “ this
". Let's take an example.
When we execute person() it takes function rule binding. When we execute line 8, it is explicitly stating what “ this
" should be, In this case, it will be obj1
. Same in case of apply
() with related to " this
".
4. Constructor Binding
“Constructors” are special methods which are attached to classes, when we are trying to invoke a function with new
keyword, the constructor of the class is called.
When a function is invoked with new
keyword in front of it, the following things will be happening
- A new object will be created.
- The new object which is constructed will be of [[prototype]] linked.
- The new object which is constructed is set as
this
binding. - It returns the newly constructed object.
In the above example, by calling person() with a new
keyword in front of it. It has constructed a new
object. The second thing is it will link to another object(prototype). The third thing is this
keyword will get bind to newly created person
object that we can see from line 2 and line 3. this.firstName
is undefined
because it is checking in that specific scope and lastName
is printing valid. And the last one is if a function doesn't return anything then it will return this
.
Overview of binding rules
We have gone through all four rules of binding this in function calls. Let's try to put it simple words
- Is there a dot? we have to look to the left, that acts like this.
- Are we seeing a .call() or .apply()? What is passed before the comma that acts like
- If we try to invoke from the context of the object then this will be? Strict mode it will be pick as undefined and in non-strict mode, it will pick the global value.
Binding exceptions
There are some exceptions to the rules. The this
keyword behaves a little weird when we are expecting apples and it gives oranges.
Ignoring “this”
If we pass null or undefined as this
parameter to either .apply, .call or .bind those values will be ignored and acts like a function binding rule.
But why any would pass null to .apply or .call? Because, when using .apply or .call null
can be passed when we have no specific value to pass for this
and we know that neither the function is also expecting this.
In the above example, there is no need of Math
in line 2, it can be passed as null
. It does not affect the output of the program.
But passing null should be avoided because if you are using a third-party library where they use this
keyword. If you pass null it will consider the value from global scope (in the browser it will be window object).
.bind() exception
When we call a function using .bind, it sets this
context and returns a function. For example,
We have one more confusion of this context and will see how it can be solved using .bind()
When we pass p.age as the callback to setTimeout we don’t invoke it. Because person
context will not be available in setTimeout
. We can fix this problem by using .bind()
In this case, we are binding our callback to this
context of the person. When it later executed, proper this
context will be passed.
Arrow functions
Normal functions have four rules what we just covered. But ES6 introduced a new function which doesn’t abide by any rules that is arrow function.
Instead of using rules, arrow functions will bind this from the enclosing scope. Let's take the above example which we solved using .bind
— END —
You can learn more about scope and hoisting here: scope in javascript
References
Originally published at https://www.allaboutjavascriptworld.com on July 2, 2020.