We will try to understand how this
works, with some concepts and examples as well.
this
has different values depending on where it is used:
So will understand this inside the following...
- Global Scope
- Objects
- Methods
- Functions (including strict mode)
- Inner Functions
- Constructor Functions
- Classes
Introduction to this
If you are inside a specific scope or object or function, this really means whichever object you are in.
There are some exceptions which we will look at
1. this
inside Global Space
Variables declared Globally (outside any function) have Global Scope.
console.log(this); // window object
this.table = 'Window Table';
console.log(window.table); // Window Table
Here in the above example table
is a property of window
object, so when we print window.table it prints the value as Window Table.
Another example -
this.garage = {
table: "Garage Table"
}
To invoke this above code, we can write it as
this.garage.table;
// Garage Table
window.garage.table;
// Garage Table
Here this
is public property of window
object because when you say this
, you are creating a public property that can be accessible from outside.
2. this
inside Object
this
inside Object is a private variable or private scoped.
Example
let SoubhagyaRoom = {
table: "Soubhagya Table"
}
Here to access My Table, we can't use this.SoubhagyaRoom.table
. It will give a TypeError saying Cannot read property 'table' of undefined. As it's not accessible.
As its a private variable we have to use it as SoubhagyaRoom.table;
3. this
inside a method
Objects can have methods as well.
In an object method,
this
refers to the "owner" of the method.
Example
let SoubhagyaRoom = {
table: "Soubhagya's Table",
cleanTable() {
console.log(`Cleaning ${this.table}`)
}
}
SoubhagyaRoom.cleanTable(); // Cleaning Soubhagya's Table
4. this
inside a Function
Example
this.table = 'Window Table';
const cleanTable = function() {
console.log(`Cleaning ${this.table}`);
}
cleanTable();
In the above example it will access the global scope and print
Cleaning Window Table
But there is an exception to
this
while using the strict mode. The same function in strict mode will result inTypeError: Cannot read property 'table' of undefined
Using 'use strict'
'use strict'
this.table = 'Window Table';
const cleanTable = function() {
console.log(`Cleaning ${this.table}`);
}
cleanTable();
Fix for this
in 'use strict'
To resolve this issue we have
call()
to the rescue
'use strict'
this.table = 'Window Table';
const cleanTable = function() {
console.log(`Cleaning ${this.table}`);
}
cleanTable.call(this);
It says, execute the cleanTable function as if its a method of this and
this
being in this case -Global Object
call() is basically used to call somebody else's method on somebody else's object.
Example
this.table = 'Window Table';
const cleanTable = function(soap) {
console.log(`Cleaning ${this.table} using ${soap}`);
}
this.garage = {
table: "Garage Table"
}
let SoubhagyaRoom = {
table: "Soubhagya's Table"
}
cleanTable.call(this, 'some soap');
// Cleaning Window Table using some soap
cleanTable.call(this.garage, 'some soap');
// Cleaning Garage Table using some soap
cleanTable.call(SoubhagyaRoom, 'some soap');
// Cleaning Soubhagya's Table using some soap
5. this
inside an Inner Function
Using 'use strict'
Example
'use strict'
this.table = 'Window Table';
const cleanTable = function(soap) {
const innerFunction = function(_soap) {
console.log(`Cleaning ${this.table} using ${_soap}`);
};
innerFunction(soap);
};
this.garage = {
table: "Garage Table"
}
let SoubhagyaRoom = {
table: "Soubhagya's Table"
}
cleanTable.call(this, 'some soap');
cleanTable.call(this.garage, 'some soap');
cleanTable.call(SoubhagyaRoom, 'some soap');
If we execute the above function then we will get
TypeError: Cannot read property 'table' of undefined
This is because inside a function using this
is not very useful unless you are using call()
or bind()
.
So to use this
inside the innerFunction
, we need to let it know it's a method of some sort or it would execute on that particular object.
To fix the issue, we have 4 solutions. Let's take a look,
Solution 1 - Define this
outside of innerFunction
'use strict'
this.table = 'Window Table';
const cleanTable = function(soap) {
let that = this;
const innerFunction = function(_soap) {
console.log(`Cleaning ${that.table} using ${_soap}`);
};
innerFunction(soap);
};
this.garage = {
table: "Garage Table"
}
let SoubhagyaRoom = {
table: "Soubhagya's Table"
}
cleanTable.call(this, 'some soap');
cleanTable.call(this.garage, 'some soap');
cleanTable.call(SoubhagyaRoom, 'some soap');
Solution 2 - Using call()
with innerFunction
'use strict'
this.table = 'Window Table';
const cleanTable = function(soap) {
const innerFunction = function(_soap) {
console.log(`Cleaning ${this.table} using ${_soap}`);
};
innerFunction.call(this,soap);
};
this.garage = {
table: "Garage Table"
}
let SoubhagyaRoom = {
table: "Soubhagya's Table"
}
cleanTable.call(this, 'some soap');
cleanTable.call(this.garage, 'some soap');
cleanTable.call(SoubhagyaRoom, 'some soap');
Solution 3 - Using bind()
with innerFunction
'use strict'
this.table = 'Window Table';
const cleanTable = function(soap) {
const innerFunction = function(_soap) {
console.log(`Cleaning ${this.table} using ${_soap}`);
};
innerFunction.bind(this)(soap);
};
this.garage = {
table: "Garage Table"
}
let SoubhagyaRoom = {
table: "Soubhagya's Table"
}
cleanTable.call(this, 'some soap');
cleanTable.call(this.garage, 'some soap');
cleanTable.call(SoubhagyaRoom, 'some soap');
Solution 4 - Using arrow function
'use strict'
this.table = 'Window Table';
const cleanTable = function(soap) {
const innerFunction = (_soap) => {
console.log(`Cleaning ${this.table} using ${_soap}`);
};
innerFunction(soap);
};
this.garage = {
table: "Garage Table"
}
let SoubhagyaRoom = {
table: "Soubhagya's Table"
}
cleanTable.call(this, 'some soap');
cleanTable.call(this.garage, 'some soap');
cleanTable.call(SoubhagyaRoom, 'some soap');
Arrow functions are special because if you want to use
this
inside a function, it doesn't really know what to do with it.But if I have an arrow function and if you use
this
inside, it will basically takethis
from the outer scope and use that.
6. this
inside a Constructor
Example
let createRoom = function(name) {
this.table = `${name}'s table`;
}
createRoom.prototype.cleanTable = function(soap) {
console.log(this)
console.log(`Cleaning ${this.table} using ${soap}`);
}
const smRoom = new createRoom('Soubhagya');
smRoom.cleanTable('some soap');
const rmRoom = new createRoom('Raghav');
rmRoom.cleanTable('some soap');
Instead of using the constructor function here, we can use classes.
7. this
inside a class
Example
class createRoom {
constructor(name) {
this.table = `${name}'s table`
}
cleanTable(soap) {
console.log(`Cleaning ${this.table} using ${soap}`)
}
}
const smRoom = new createRoom('Soubhagya');
smRoom.cleanTable('some soap');
const rmRoom = new createRoom('Raghav');
rmRoom.cleanTable('some soap');
When we have a class, it pretty much does the same thing that a constructor function does and it has a prototype method called cleanTable.