20
JavaScript: Simplifying 'this'
this
in any scope is equivalent to the object, implicitly it's the object from it is being call called as you must have read this
depends on the call site, how and where the function is being called. Explicitly you can set this
too, using bind
, call
or apply
we will cover these later.
A simple example
var obj = {
age: 2,
printAge: function () {
console.log(this.age);
},
};
obj.printAge(); // 2
Arrow functions are not just syntactical sugar over the normal function apart from other differences, one major difference is value of this
it follows the lexical static binding i.e. this
is not dynamic anymore. this
is same as this
of outer lexical scope. What does outer lexical scope mean?
Scope of the the parent function!
const x = {
y: 2,
x1: {
m1: () => console.log(1, this),
},
x2: function () {
const y2 = {
m1: () => console.log(2, this),
m2: function () {
const y3 = {
m3: () => console.log(3, this),
};
return y3;
},
};
return y2;
},
};
x.x2().m1(); // 2, {y: 2, x1: Object, x2: ƒ x2()}
x.x2().m2().m3(); // 3, {m1: ƒ m1(), m2: ƒ m2()}
All function which are defined on top level are defined on window
object hence this === windows
for top level functions. this
is undefined
with strict mode enabled or with modules.
Let's take an example
var a = 1;
function incA() {
this.a = this.a + 1;
}
incA();
console.log(a); // 2
Note: The above example holds only for "script" not "module", it will work in browser console's but not in CodeSandBox for the same reason.
There are some rules, relevant one for our discussion are
- Arrow function can't be used as constructor.
-
this
in arrow will be equal to the instance of this class. How? Checkout: Transpiled code sample for Class
Let's take an example
class X {
name = 2;
method1() {
console.log(this.name);
}
method2 = () => {
console.log(this.name);
};
}
const z = new X();
z.method1(); // 2
z.method2(); // 2
let's add two more method
class X {
name = 2;
method1() {
console.log(this.name);
}
method2 = () => {
console.log(this.name);
};
method3() {
this.method1();
}
method4 = () => {
this.method2();
};
}
const z = new X();
z.method3(); // 2
z.method4(); // 2
Still nothing changes as method3
is being called for the the object (z
) itself so it got the context and method4
has static binding.
Add the following code in the end:
const method5 = z.method3;
const method6 = z.method4;
method6(); // 2
method5(); // TypeError: Cannot read property 'method1' of undefined
As method5
has now lost the context it can't point to this
, you must be wondering why it throws error instead of undefined
as we discussed initially!
Module ? Nope, not this time!
It's due to implementation of class. Class are defined as function inside immediately invoked function expression.
That's why it's important to bind function in React. Not all but only those which will be passed to event handler or similar pattern as they are gonna loose the context of the component instance or use arrow functions.
There might be a case where you would like to call a method from one object with another object for example
This example will be used throughout the section
const square1 = {
side: 5,
getArea: function () {
return this.side * this.side;
},
};
const square2 = {
side: 10,
};
console.log(square1.getArea()); // 25
console.log(square1.getArea.call(square2)); //100
// This will work as well
const getArea = square1.getArea;
console.log(getArea.call(square2)); //100
// This too
const getArea2 = square1.getArea.bind(square2);
console.log(getArea2()); //100
With call
you can specify the object while calling a method and with each call you can pass another object.
const square3 = {
side: 20,
};
console.log(getArea.call(square3)); //400
bind
is one time contract, once a method have formed bond with an object, it can't be broken, you cannot bind
that again or use call
on it.
// const getArea2 = square1.getArea.bind(square2);
console.log(getArea2()); //100
console.log(getArea2.call(square3));
const getArea3 = getArea2.bind(square3); // 100
console.log(getArea3()); // 100
apply
is same as call
, it just expects array of parameters instead of individual parameters.
--EOF--
20