Let’s explore what ‘this’ is all about and also understand what is Dynamic Scope and Lexical Scope.
Simply, ‘this’ is the object that the function is a property of and it also depends on what is to the left side of the dot on the calling function. It means that we have an object and this object has some functions, inside of these functions, when we do something, we have access to the ‘this’ keyword.
Here’s an example,
console.log(this)
function a() {
console.log(this)
}
// Output
> window
> window
Both are returning the same object, its really confusing, right! Well if you have read my previous article where I’ve mentioned that, when a global execution context is created, we get ‘this’ keyword but also when we create new function or execution context, we have ‘this’ as well.
The example below will show how ‘this’ can be really helpful,
const obj = {
make: 'Apple'
model: function() {
return this.make + 'M1'
}
}
model()
So remember our definition of ‘this’, well in our example, ‘this’ refers to the object which function model() is a property of. Here we have written ‘this.make’ because in case, if there is some change in the property ‘model’, we don’t need to change it manually everywhere, ‘this’ will take care of it.
Also with ‘this’, multiple objects can execute the same code. Let me show what I mean,
function laptop() {
console.log(this.make + ' ' + this.model)
}
const make = 'Dell'
const model = 'Inspiron'const obj1 = {
make: 'Apple'
model: 'M1'
laptop: laptop
}
const obj2 = {
make: 'HP'
model: 'Victus'
laptop: laptop
}
obj1.laptop()
obj2.loptop()
laptop()
// Output
> Apple M1
> HP Victus
> Dell Inspiron
In the code above, we have a function which simply returns the make and model of a laptop from the object where it is called from. In obj1, we are calling the function so that we get returned ‘Apple M1’ and same with the obj2. So now we can update or change the properties of an object but still get the desired output using ‘this’ instead of hard coding the values in a function/property. It also makes our code DRY, simpler and more cleaner.
The ‘this’ keyword is dynamically scoped which means it does not matter where its written but how the function was called. Dynamic scoping uses the location of the function’s invocation to determine which variables are available and on the other hand, lexical scope refers to when the location of a function’s definition determines which variable you have access to.
const one = function() {
console.log(this)
const two = function() {
console.log(this)
const three = {
a: function() {
console.log(this)
}
}
three.a()
}
two()
}
one()
// Output
> window
> window
> three
In the piece of code above, we have a function one() which has another function two() and in that we have an object three, which contains another function a() and every function just print the value of ‘this’ in which the a function is a property of, to the console. We get the window object for both the functions one() and two(), because one() was called by the window as it is in the global execution context. But who called two()? There is nothing to the left side of the dot or no other object that called it, so the ‘this’ still refers to window object. It looks something like this,
window.one(two())
As soon as we called three.a(), the ‘this’ changes to the object three, because to the left of the calling function there is object three which means it is called by object ‘three’.
In this case, the lexical environment doesn’t really matter where we write the code, all it matters is how it gets called or who calls it.
const animal = {
name: 'cat'
sound() {
console.log(this)
var variation() = function() {
console.log(this)
}
}
}
animal.sound()
// Output
> animal
> window
Now why is the ‘this’ inside variation() referring to the window object? As I mentioned above that the ‘this’ keyword is not lexically scoped, it is dynamically scoped. So here, we ran animal.sound() and in that function another function variation() got ran, which means the ‘animal’ object didn’t called the function but the sound did. And in JavaScript, the ‘this’ keywords automatically gets referred to the window object if there is nothing to the left of it.
It create a lot of confusions, so how this problem can be fixed? We can solve this issue by using the arrow functions ‘=>’ which was introduced in ES6, arrow functions are lexically bound which means it has lexical behavior of ‘this’,
var variation = () => {
console.log(this)
}
So now if we run the function variation(), we are going to get back the animal object. When we declare functions like the above, its going to lexically bind ‘this’.
Great, now our problem is solved! But here’s a question, how people used to solve this back in the days before ES6 got released? It was done by returning the function and bind it to ‘this’.
var variation() = function() {
console.log(this)
}
return variation.bind(this)animal.sound()()
// Output
> animal
There are two pairs of brackets to call the function inside of a function.
There’s another method to solve this, just declare a reference variable which refers to ‘this’.
const animal = {
name: 'cat'
sound() {
console.log(this)
var self = this
var variation() = function() {
console.log(self)
}
}
}
animal.sound()
// Output
> animal
> animal
Thanks!
Top comments (0)