Chapter 3.1 This keyword
What does this
keyword mean ?
A function's this keyword behaves a little differently in JavaScript compared to other languages. It also has some differences between strict mode and non-strict mode.
In most cases, the value of this
is determined by how a function is called (runtime binding). It can't be set by assignment during execution, and it may be different each time the function is called.
In JavaScript, the this
keyword refers to an object.
Which object depends on how this
is being invoked (used or called).
The this
keyword refers to different objects depending on how it is used:
- In an object method,
this
refers to the object. - Alone,
this
refers to the global object. - In a function,
this
refers to the global object. - In a function, in strict mode,
this
isundefined
. - an event,
this
refers to the element that received the event. - Methods like call(), apply(), and bind() can refer
this
to any object.
In javascript This keyword is not statically bound which implies we cannot determine what value does this
keyword holds by simply looking at the function or the function defination, we also have to look for where the function is executed and how this
value changes
Before moving forward lets look at the below questions to get a brief context about this and how it works
const object = {
firstName: "Pratyush",
print: function () {
console.log(this.firstName);
},
};
setTimeout(object.print, 100);
Output
undefined
var object = {
firstName: "Pratyush",
friends: ["Subhankar", "Rajat"],
loop: function () {
this.friends.forEach(function (friend) {
console.log(this.firstName + " knows " + friend);
});
},
};
object.loop();
Output
"undefined knows Subhankar"
"undefined knows Rajat"
But instead of undefined Pratyush should come right? Not in this case.
Before we proceed ahead lets discuss briefly about Object Methods
Object Methods
Methods are actions that can be performed on objects. That means in javascript functions can become methods when the functions are put inside an obejct example:
const object = {
firstName: "Pratyush",
print() {
console.log(this.firstName);
},
};
object.print();
Output
"Pratyush"
this
inside methods ?
-
Unlike other languages (like JAVA ), the
this
is not bound to any specific object in JavaScript -
The
this
value can be modified in a couple of ways.- Default binding (when no obejct is supplied)
- Implicit binding (when an object is supplied naturally)
- Arrow functions (when arrow functions are used)
- Explicit binding (when call bind or apply is used)*
- new Binding (when
new
keyword is used)* - strict mode (when using
use strict
keyword)* - contextual (libraries or framework may change values for ex: Event emmiters)*
* : we are not covering here for now.
Important Rules regarding this
keyword
this
keyword is not an compile time binding but a run time binding i.e we cannot say what value will thethis
keyword will hold just by looking the code we have to execute that to find out the same.this
keyword has nothing to do with where and how the function is declared but have everything to do how that function is called or invoked
1. Default binding
- standalone function invocation
- if no other binding rule matches, then it is default binding it sort of works like default catch-all rule.
function print() {
// points global in node.js
// points window in a browser
console.log(this.firstName);
}
print();
Output
undefined
global = {
firstName: "Pratyush",
};
function print() {
// points global in node.js
// points window in a browser
console.log(this.firstName);
}
global.print = print;
global.print();
Output
Pratyush
2. Implicit binding
Implicit binding rule says that it's adjoining object which should be used for the function call's this binding
function foo() {
// here this = object when called like object.foo()
console.log(this.a);
}
const object = { a: 2, foo: foo };
foo(); // global context has a: undefined
object.foo();
Output
undefined
2
lets see one problem that can occur :
Implicit lost
One of the most common frustrations that this
binding creates is when an implicitly bound function loses that binding, which usually means it falls back to the default binding, of either the global object or undefined
, depending on strict mode.
function foo() {
console.log(this === global);
// here this = object when called like object.foo()
console.log(this.a);
}
const object = { a: 2, foo: foo };
var fn = object.foo;
fn(); // refers to the global scope
console.log("-----------");
object.foo(); // refers to the object scope
Output
true
undefined
-----------
false
2
Pitfalls
loosing this while extracting a method.
var counter = {
count: 0,
increment: function () {
console.log("increment was called.");
this.count++;
},
};
var fn = counter.increment;
fn();
setTimeout(counter.increment, 1000);
setTimeout(() => {
console.log(counter.count);
}, 2000);
setTimeout(() => {
console.log(global.count);
}, 2000);
Output
increment was called.
0
NaN
- we have called the value of
counter.increment
as a function - Hence this is the global object and we have performed window.count++
- window.count doesnot exist and is undefined applying ++ operators sets it to NaN
3. Arrow function
Arrow functions were introduced in ES6.
Arrow functions allow us to write shorter function syntax:
let myFunction = (a, b) => a * b;
It gets shorter! If the function has only one statement, and the statement returns a value, you can remove the brackets and the return keyword:
const arr = [1, 2, 3];
const squares = arr.map((x) => x * x); // one parameter
the complete list of variables whose values are determined lexically is :
- arguments
- super
- this
- new.target
If we look into the very first question we can make it work like this:
- keeping this under a scoped variable
var object = {
firstName: "Pratyush",
friends: ["Subhankar", "Rajat"],
loop: function () {
var that = this;
this.friends.forEach(function (friend) {
console.log(that.firstName + " knows " + friend);
});
},
};
object.loop();
Output
Pratyush knows Subhankar
Pratyush knows Rajat
- bind()
var object = {
firstName: "Pratyush",
friends: ["Subhankar", "Rajat"],
loop: function () {
this.friends.forEach(
function (friend) {
console.log(this.firstName + " knows " + friend);
}.bind(this)
);
},
};
object.loop();
Output
Pratyush knows Subhankar
Pratyush knows Rajat
- a thisValue for forEach()
var object = {
firstName: "Pratyush",
friends: ["Subhankar", "Rajat"],
loop: function () {
this.friends.forEach(function (friend) {
console.log(this.firstName + " knows " + friend);
}, this);
},
};
object.loop();
Output
Pratyush knows Subhankar
Pratyush knows Rajat
- Using Arrow functions
var object = {
firstName: "Pratyush",
friends: ["Subhankar", "Rajat"],
loop: function () {
this.friends.forEach((friend) => {
console.log(this.firstName + " knows " + friend);
});
},
};
object.loop();
Output
Pratyush knows Subhankar
Pratyush knows Rajat
Like my blogs ?
You can give this github repo a ⭐Here