JavaScript's this
keyword is notorious for confusing developers at all levels.
In this guide, we'll explore the inner workings of the 'this' keyword in JavaScript and how it behaves in different contexts.
It is commonly used in object-oriented programming languages to differentiate between class attributes and method parameters with the same name, as well as to access the current object's properties and methods
1class Car {
2 // instance variables
3 type = 'hatchback';
4
5 // constructor
6 constructor(type) {
7 // this.type refers to the instance variable
8 // type refers to the parameter or argument of the constructor
9 this.type = type;
10 }
11}
We don't need to use this
keyword when there is no ambiguity.
1class Car {
2 model = 'Toyota';
3
4 constructor(modelArg) {
5 // There is no ambiguity here, so 'this' is not needed
6 model = modelArg;
7 }
8}
In JavaScript, the this
keyword is a reference to an object, but its value depends on how and where it is used (Execution Context).
Here are the general rules for where this points to:
When used in the global context (outside of any function), this refers to the global object (window in browsers).
1console.log(this); // window
2
3console.log(this === window); // true
4
This behavior changes in strict mode, where this
is undefined
instead of the global object.
1'use strict';
2
3console.log(this); // undefined
4
5console.log(this === window); // false
When used inside a function, this refers to the object that called the function.
1const getThis = function() {
2 console.log(this);
3}
4
5// window, since getThis is called in the global context
6getThis();
Diagram Loading...
When function is a property of an object, this refers to the object itself.
1const person = {
2 name: 'John',
3 sayName: function() {
4 console.log(this);
5 console.log(this.name);
6 }
7}
8
9// { name: 'John', sayName: [Function: sayName] }
10// John
11person.sayName();
Diagram Loading...
If the function is assigned to a variable, this refers to the global object. (since its not part of the object anymore)
1const { sayName } = person;
2
3// window
4// undefined
5sayName();
Diagram Loading...
When used inside a constructor function, this refers to the instance of the object being created.
1class Person {
2 name = 'John';
3
4 constructor(name) {
5 this.name = name;
6 }
7
8 getName() {
9 console.log(this);
10 return this.name;
11 }
12}
13
14const person = new Person('Jane');
15
16// { name: 'Jane', getName: [Function: getName] }
17console.log(person.getName()); // Jane
18
Diagram Loading...
However, if the class function is assigned to a variable, this refers to undefined, as it is not part of the class anymore.
1 const { getName } = person;
2getName(); // undefined
Diagram Loading...
JS executes classes in strict mode by default (mandated). This explains the difference in behavior between the "Function extracted from objects" and "Function extracted from classes" examples.
If the method is a static method, this refers to the constructor function (class) itself.
1class Person {
2 value = 10;
3
4 static getValue() {
5 console.log(this); // [Function: Person]
6 return this.value; // undefined
7 }
8}
9
10console.log(Person.getValue()); // undefined
When used in a function constructor, this refers to the instance of the object being created.
1function Person(name) {
2 this.name = name;
3 this.getName = function() {
4 return this.name;
5 }
6}
7
8const person = new Person('John');
9person.getName(); // John
Don't forget to use the new keyword when creating a new instance of the object. Forgetting to use the new keyword will result in global object pollution.
1const person = Person('John');
2console.log(person); // undefined
3
4// global object pollution
5// console.log(window.name); if you are using a browser
6console.log(globalThis.name); // John
When used as an event handler, this refers to the element that triggered the event.
1document.body.addEventListener('click', function () {
2 console.log(this); // <body>
3});
Diagram Loading...
When used as a callback function for a timer, this refers to the Timer object.
1setTimeout(function() {
2 console.log(this); // Timeout object
3});
1const john = {
2 name: 'John',
3 sayName: function(arg1, arg2) {
4 console.log(this.name);
5 console.log({ arg1, arg2 });
6 }
7}
8
9const jane = {
10 name: 'Jane',
11};
If you want to explicitly set the value of this
, you can use the following methods:
Executes a function with the execution context of another object.
1john.sayName.call(jane, 'value1', 'value2');
2// Jane { arg1: 'value1', arg2: 'value2' }
Here sayHello() function is executed with the context of jane, instead of john.
Diagram Loading...
Similar to call(), but takes an array of arguments.
1john.sayName.apply(jane, ['value1', 'value2']);
2// Jane { arg1: 'value1', arg2: 'value2' }
Creates a new bounded function that, when called, has its this keyword set to the provided value.
1const boundFunction = john.sayName.bind(jane, 'value1', 'value2');
2boundedFunction();
3// Jane { arg1: 'value1', arg2: 'value2' }
Javascript Arrow functions do not have their own this value. Instead, they inherit the this value from the enclosing lexical context.
Diagram Loading...
Object literals do not create a new lexical scope. The this value in this case refers to the scope in which the object was declared.
1const person = {
2 name: 'John',
3 sayName: function() {
4 console.log(this);
5 console.log(this.name);
6 }
7}
8
9// { name: 'John', sayName: [Function: sayName] }
10// John
11person.sayName();
1class Person {
2 name = 'John';
3
4 constructor(name) {
5 this.name = name;
6 }
7
8 getName() {
9 return this?.name;
10 }
11
12 getNameArrow = () => {
13 return this?.name;
14 };
15}
16
17const person = new Person('Jane');
1function Person(name) {
2 this.name = name;
3
4 this.getName = function() {
5 return this.name;
6 }
7
8 this.getNameArrow = () => {
9 return this.name;
10 }
11}
12
13const person = new Person('John');
When getName()
and getNameArrow()
function are called using the person instance. They both have the same value of this.
getName()
- gets the this value from the person instance due to object context.getNameArrow()
- gets the this value from the lexical context of the arrow function.1person.getName(); // John
2person.getNameArrow(); // John
When getName()
is called after being assigned to a variable, it loses its object context and this refers to the global object.
1const { getName, getNameArrow } = person;
2getName(); // undefined
3getNameArrow(); // John
Understanding the 'this' keyword is crucial for writing maintainable and bug-free code in JavaScript. It is a complex topic that requires practice to master.
By using arrow functions and explicit binding, you can avoid the confusion and pitfalls associated with the 'this' keyword.