The 'this' keyword in JS
The this
keyword in JavaScript refers to the object of its current execution context. In other words, the value of this
is determined based on how the function is called.
The main purpose of this
is to give methods access to their objects and to make our code reusable by allowing us to execute the same code for multiple objects.
Let's explore how the
this
keyword gets its value and how we can stabilize it.
Global execution
The this
keyword is immediately available. Open your DevTools in the console and type this
. The value of this
is the Window object
.
// output: Window { …} console.log(this)
Invocation as function
If we are simply invoking a function statement or a function expression, the this
keyword will also point to the Window object
, because the function execution context is global.
function myFunction() { // output: Window { …} console.log(this) /* myVariable is on the global scope and it will be inside the Window object. */ this.myVariable = "global" }
Methods
A method is a function definition inside an object. We invoke methods with the dot notation: myObject.myMethod()
. The execution context is myObject
, and the this
keyword points to current object.
const myObject = { myMethod: function () { // 'this' === myObject console.log(this) }, } myObject.myMethod()
However, if we add a new function inside myMethod
, we create a new execution context and the this
keyword now points to global scope.
const myObject = { myMethod: function () { setTimeout(function () { // output: Window { …} console.log(this) }) }, }
Next, we will explore a few ways to stabilize the value of this
to prevent this unwanted behavior.
Assigning 'this' to a variable
We can explicitly point this
to the current object by assigning its value to a variable. Example: var self = this;
- This is an outdated solution commonly seen on legacy code.
const myObject = { myMethod: function () { var self = this setTimeout(function () { // self === myObject console.log(self) }) }, }
Bind
The bind()
method sets the value of this
to a particular value regardless of how it is called. In the following example, we explicitly bind this
to the callback function to maintain its instance.
const myObject = { myMethod: function () { setTimeout( function () { // output: myObject { …} console.log(this) }.bind(this) ) }, }
Call and Apply
The call()
and apply()
methods, call a function with a given this
value. The difference between the two methods relies on how they accept their arguments.
The first argument should be bound to this.
const wine = { name: "Bordeaux", price: 18.5, } function getProduct() { // output: The price of Bordeaux is 18.5 dlls. console.log(`The price of ${this.name} is ${this.price} dlls.`) } // this === wine by passing the wine object as an argument getProduct.call(wine) getProduct.apply(wine)
call()
accepts an argument list as the second parameter.
const wine = { name: "Bordeaux", price: 18.5, } function getProduct(status, date) { // output: Bordeaux is not available today. console.log(`${this.name} is ${status} ${date}`) } getProduct.call(wine, "not available", "today")
apply()
accepts a single array of arguments as the second parameter.
const wine = { name: "Bordeaux", price: 18.5, } function getProduct(params) { /* output: Bordeaux is not available today. */ console.log(`${this.name} is ${params[0]} ${params[1]}`) } getProduct.call(wine, ["not available", "today"])
Arrow functions (ES6)
In regular functions, the this
keyword gets its value from the object that called the function. Arrow functions don't have binding of this
and the this
keyword always represents the object that defined the arrow function.
const myObject = { myMethod() { // this === myObject setTimeout(() => console.log(this)) }, }
Strict mode
Strict mode can help us prevent some silent errors by changing them to throw errors. The this
keyword has some differences between strict mode and non-strict mode. In strict mode
, the global this
keyword is undefined.
"use strict" function myFunction() { // output: undefined console.log(this) }
Hey, I'm Ignacio Villamar
Senior Frontend Engineer, living in the NYC metro area.
Follow @ivstudio