Summary: in this tutorial, you will learn about the JavaScript this value and understand it clearly in various contexts.
What is this keyword #
The this refers to the object that owns the function or method currently being executed. When you call a method on a object, this will reference to that object.
For example, if you have a car object with the start method, this inside the start method will refer to the car object itself:
let car = {
brand: 'Honda',
start: function() {
// "this" is the car object
console.log(this.brand + ' is starting.');
}
};
car.start(); // Output: "Honda is starting."Global context #
In the global context, the this references the global object, which is the window object on the web browser or global object on Node.js.
This behavior is consistent in both strict and non-strict modes. Here’s the output on the web browser:
console.log(this === window); // trueIf you assign a property to this object in the global context, JavaScript will add the property to the global object as shown in the following example:
this.color= 'Red';
console.log(window.color); // 'Red'Function context #
The value of this depends on how you call a function. There are four main ways:
1) Simple function calls #
When you call a function, the value of this depends on an the mode of the script:
- Non-strict mode:
thisrefers to the global object. For example, on web browserthisis thewindowobject. - Strict mode:
thisisundefined. To enable the strict mode, you place the"use strict"; statement at the top of the JavaScript file or function. The statement preventsthisfrom accidentally referencing the global object.
For example:
function show() {
console.log(this === window); // true
}
show();When you call the show() function, the this references the global object, which is the window on the web browser and global on Node.js.
Calling the show() function is the same as:
window.show();In the strict mode, JavaScript sets the this inside a function to undefined. For example:
"use strict";
function show() {
console.log(this === undefined);
}
show(); // trueNote that the strict mode has been available since ECMAScript 5.1. The strict mode applies to both function and nested functions. For example:
function show() {
"use strict";
console.log(this === undefined); // true
function display() {
console.log(this === undefined); // true
}
display();
}
show();Output:
true
trueIn the display() inner function, the this also set to undefined as shown in the console.
2) Method calls #
When you call function as a method of an object, this refers to the object itself. This is the most common way of using the this object. For example:
let car = {
brand: 'Honda',
getBrand: function () {
return this.brand;
}
}
console.log(car.getBrand()); // HondaIn this example, the this object in the getBrand() method references the car object.
Since a method is a property of an object which is a value, you can store it in a variable.
let brand = car.getBrand;And then call the method via the variable
console.log(brand()); // undefinedYou get undefined instead of "Honda" because when you call a method without specifying its object, JavaScript sets this to the global object in non-strict mode and undefined in the strict mode.
To fix this issue, you can use the bind() method of the Function.prototype object. The bind() method creates a new function whose the this keyword is set to a specified value.
let brand = car.getBrand.bind(car);
console.log(brand()); // HondaIn this example, when you call the brand() method, the this keyword is bound to the car object. For example:
let car = {
brand: 'Honda',
getBrand: function () {
return this.brand;
}
}
let bike = {
brand: 'Harley Davidson'
}
let brand = car.getBrand.bind(bike);
console.log(brand());Output:
Harley DavidsonIn this example, the bind() method sets the this to the bike object, therefore, you see the value of the brand property of the bike object on the console.
3) Constructor calls #
When you use the new keyword to create an instance of a function object, you use the function as a constructor.
The following example declares a Car function, and then calls it as a constructor:
function Car(brand) {
this.brand = brand;
}
Car.prototype.getBrand = function () {
return this.brand;
}
let car = new Car('Honda');
console.log(car.getBrand());The expression new Car('Honda') is a constructor invocation of the Car function.
JavaScript creates a new object and sets this to the newly created object. This pattern works great with only one potential problem.
Now, you can invoke the Car() as a function or as a constructor. If you omit the new keyword as follows:
var bmw = Car('BMW');
console.log(bmw.brand);
// => TypeError: Cannot read property 'brand' of undefinedSince the this value in the Car() sets to the global object, the bmw.brand returns undefined.
To make sure that the Car() function is always invoked using constructor invocation, you add a check at the beginning of the Car() function as follows:
function Car(brand) {
if (!(this instanceof Car)) {
throw Error('Must use the new operator to call the function');
}
this.brand = brand;
}ES6 introduced a meta-property named new.target that allows you to detect whether a function is invoked as a simple invocation or as a constructor.
You can modify the Car() function that uses the new.target metaproperty as follows:
function Car(brand) {
if (!new.target) {
throw Error('Must use the new operator to call the function');
}
this.brand = brand;
}4) Indirect calls #
In JavaScript, functions are first-class citizens. In other words, functions are objects, which are instances of the Function type.
The Function type has two methods: call() and apply() . These methods allow you to set the this value when calling a function. For example:
function getBrand(prefix) {
console.log(prefix + this.brand);
}
let honda = {
brand: 'Honda'
};
let audi = {
brand: 'Audi'
};
getBrand.call(honda, "It's a ");
getBrand.call(audi, "It's an ");Output:
It's a Honda
It's an AudiIn this example, we called the getBrand() function indirectly using the call() method of the getBrand function. We passed honda and audi object as the first argument of the call() method, therefore, we got the corresponding brand in each call.
The apply() method is similar to the call() method except that its second argument is an array of arguments.
getBrand.apply(honda, ["It's a "]); // "It's a Honda"
getBrand.apply(audi, ["It's an "]); // "It's a Audi"Arrow functions: A special case #
ES6 introduced a new concept called the arrow function. In arrow functions, JavaScript sets the this lexically.
It means arrow functions do not create its own execution context but inherits the this from the outer function where the arrow functions are defined. For example:
let getThis = () => this;
console.log(getThis() === window); // trueIn this example, the this value is set to the global object i.e., window in the web browser.
Since an arrow function does not create its own execution context, defining a method using an arrow function will cause an issue. For example:
function Car() {
this.speed = 120;
}
Car.prototype.getSpeed = () => {
return this.speed;
};
var car = new Car();
console.log(car.getSpeed()); // 👉 undefinedInside the getSpeed() method, the this value reference the global object, not the Car object but the global object doesn’t have a property called speed. Therefore, the this.speed in the getSpeed() method returns undefined.
Summary #
- The
thiskeyword refers to object that’s currently execute a function. - When you call a function, the
thisinside the function refers to the global object in non-strict mode orundefinedin strict mode. - When you call a function as a method of an object, this refers to the object that owns the method.
- When you use a function as a constructor with the
newkeyword,thisis set to newly created object. - The
call()andapply()methods allow you to explicitly set the value ofthiswhen you call a function. - Arrow functions do not have their own
this. Instead, they usethisfrom the surrounding code where they were defined.
Thank you for your feedback!