Many JavaScript developers try to avoid using the this
keyword. One reason is that what this
refers to changes. This guide will help you with it. You will learn what this
keyword refers to in specific contexts. This will make it easier for you to work with it and help you predict what to expect when you use it.
Quick introduction
The this
is a special keyword in JavaScript. There is one problem JavaScript developers struggle with when they learn about this
. It can have different values. It can refer to different things. What determines what this
refers to is context, the context at which you use it. Let's take a look at these contexts and what to expect from this
keyword in each of them.
Strict and sloppy mode
In JavaScript, there are two modes or variants of JavaScript you can work with. The first one is strict mode. The second one is sloppy mode. By default, you write your JavaScript code in a sloppy mode. This mode is more ... sloppy. It allows you to do things that would be forbidden in a strict mode. These things would not work.
JavaScript offers you an option to switch from sloppy mode to strict mode. You can do this by using 'use strict'
statement at the beginning of your code. Any code that follows after this statement will automatically follow the rules and restrictions of strict mode. This also includes the this
keyword.
Global scope
When you are in a global scope, the this
keyword will refer to the global object window
. This is the case at least if you are in the browser. If you are in a Node.js environment, the this
will refer to global object called global
. In a global scope, it doesn't matter if you are in a sloppy mode or a strict mode.
// Global context example no.1: sloppy mode
console.log(this)
// Output:
// Window {0: Window, 1: Window, window: Window, self: Window, document: document, name: "", location: Location, …}
// In Node.js:
console.log(this)
// Output:
// <ref *1> Object [global] {
// global: [Circular *1],
// clearInterval: [Function: clearInterval],
// clearTimeout: [Function: clearTimeout],
// setInterval: [Function: setInterval],
// setTimeout: [Function: setTimeout] {
// [Symbol(nodejs.util.promisify.custom)]: [Getter]
// },
// queueMicrotask: [Function: queueMicrotask],
// clearImmediate: [Function: clearImmediate],
// setImmediate: [Function: setImmediate] {
// [Symbol(nodejs.util.promisify.custom)]: [Getter]
// }
// }
// Global context example no.2: strict mode
// Switch to strict mode.
'use strict'
console.log(this)
// Output:
// Window {0: Window, 1: Window, window: Window, self: Window, document: document, name: "", location: Location, …}
// In Node.js:
console.log(this)
// Output:
// <ref *1> Object [global] {
// global: [Circular *1],
// clearInterval: [Function: clearInterval],
// clearTimeout: [Function: clearTimeout],
// setInterval: [Function: setInterval],
// setTimeout: [Function: setTimeout] {
// [Symbol(nodejs.util.promisify.custom)]: [Getter]
// },
// queueMicrotask: [Function: queueMicrotask],
// clearImmediate: [Function: clearImmediate],
// setImmediate: [Function: setImmediate] {
// [Symbol(nodejs.util.promisify.custom)]: [Getter]
// }
// }
Functions
When it comes to [functions], the mode at which you are makes a difference for the this
keyword. When you are in sloppy mode, this
will refer to the global object window
. Global object global
in Node.js. This is true even for functions declared inside another functions, in a local scope.
// Function example no.1: function in a global scope
// Declare a function.
function foo() {
// Log the value of this
console.log(this)
console.log(this === window)
}
// Invoke foo() function.
foo()
// Output:
// Window {0: Window, 1: Window, window: Window, self: Window, document: document, name: "", location: Location, …}
// true
// Function example no.2: function in a local scope
// Declare a function.
function foo() {
return function bar() {
// Log the value of this
console.log(this)
console.log(this === window)
}
}
// Invoke foo() and bar() functions.
foo()()
// Output:
// Window {0: Window, 1: Window, window: Window, self: Window, document: document, name: "", location: Location, …}
// true
Strict mode
This will change if you switch your JavaScript code to strict mode. In a strict mode, the default value of this
in a function is set to undefined
.
// Strict mode example no.1: function in a global scope
// Switch to strict mode.
'use strict'
// Declare a function.
function foo() {
// Log the value of this
console.log(this)
console.log(this === window)
}
// Invoke foo() function.
foo()
// Output:
// undefined
// false
// Strict mode example no.2: function in a local scope
// Switch to strict mode.
'use strict'
// Declare a function.
function foo() {
return function bar() {
// Log the value of this
console.log(this)
console.log(this === window)
}
}
// Invoke foo() and bar() functions.
foo()()
// Output:
// undefined
// false
Immediately Invoked Function Expression (IIFE)
The this
keyword works in IIFEs like in regular functions. In a sloppy mode, this
will refer to the global object window
. If you switch to a strict the value of this
will become undefined
.
// IIFE example no.1: sloppy mode
// Declare IIFE.
(function() {
console.log(this)
console.log(this === window)
})()
// Output:
// Window {0: Window, 1: Window, window: Window, self: Window, document: document, name: "", location: Location, …}
// true
// IIFE example no.2: strict mode
// Switch to strict mode.
'use strict';
// Declare IIFE.
(function() {
console.log(this)
console.log(this === window)
})()
// Output:
// undefined
// false
Function constructors
When you want to create new functions with similar behavior you can use function constructor. This allows you to create a blueprint you can then use for your functions. If you use function constructor remember one thing. The this
keyword inside a constructor will refer to the instance of that constructor, not the constructor itself. This applies to both, sloppy and strict mode.
// Function constructors example no.1: sloppy mode
// Create function constructor Person.
function Person(name, age) {
this.name = name
this.age = age
this.readPerson = function() {
console.log(this)
}
}
// Create joe instance.
const joe = new Person('Joe', 31)
// Create natalie instance.
const natalie = new Person('Natalie', 28)
// Invoke readPerson() method on joe instance.
joe.readPerson()
// Output:
// Person {
// name: 'Joe',
// age: 31,
// readPerson: ƒ (),
// __proto__: Person { constructor: ƒ Person() }
// }
// Invoke readPerson() method on natalie instance.
natalie.readPerson()
// Output:
// Person {
// name: 'Natalie',
// age: 28,
// readPerson: ƒ (),
// __proto__: Person { constructor: ƒ Person() }
// }
// Function constructors example no.2: strict mode
// Switch to strict mode.
'use strict'
// Create function constructor Person.
function Person(name, age) {
this.name = name
this.age = age
this.readPerson = function() {
console.log(this)
}
}
// Create joe instance.
const joe = new Person('Joe', 31)
// Create natalie instance.
const natalie = new Person('Natalie', 28)
// Invoke readPerson() method on joe instance.
joe.readPerson()
// Output:
// Person {
// name: 'Joe',
// age: 31,
// readPerson: ƒ (),
// __proto__: Person { constructor: ƒ Person() }
// }
// Invoke readPerson() method on natalie instance.
natalie.readPerson()
// Output:
// Person {
// name: 'Natalie',
// age: 28,
// readPerson: ƒ (),
// __proto__: Person { constructor: ƒ Person() }
// }
Objects and methods
When you use this
keyword in an object method, the result can vary. What matters is if the method is a regular function or an arrow function. You will learn about this
and arrow functions later. For now, let's focus on regular functions.
When you use this
in an object method, it will refer to the object itself. This is for both, sloppy as well as strict mode.
// Object example no.1: sloppy mode
const myObj = {
name: 'Jack',
age: 30,
readObj() {
console.log(this)
}
}
// Invoke the readObj() method on myObj.
myObj.readObj()
// Output:
// { name: 'Jack', age: 30, readObj: ƒ readObj() }
// Object example no.2: strict mode
// Switch to strict mode.
'use strict'
const myObj = {
name: 'Jack',
age: 30,
readObj() {
console.log(this)
}
}
// Invoke the readObj() method on myObj.
myObj.readObj()
// Output:
// { name: 'Jack', age: 30, readObj: ƒ readObj() }
Classes
JavaScript classes are a newer addition to JavaScript. They are definitely one of those more discussed features. Some developers like to use them and some not. If you like using them, or want to start using them, you will like what follows. When it comes to classes, the this
keyword is very consistent and predictable.
It doesn't matter if you are in a sloppy mode or a strict mode. If you use this
in a class it will refer to the class itself.
// Classes example no.1: with instantiation in sloppy mode (regular function, no binding)
// Declare a class with public property and method.
class Person {
constructor(name) {
this.name = name
}
sayHi() {
console.log(this)
}
}
// Instantiate the Person class.
const joshua = new Person('Joshua')
// Invoke sayHi() on "joshua" instance.
joshua.sayHi()
// Output:
// Person {name: "Joshua"}
// Classes example no.2: with instantiation in sloppy mode (arrow function)
// Declare a class with public property and method.
class Person {
constructor(name) {
this.name = name
}
sayHi = () => {
console.log(this)
}
}
// Instantiate the Person class.
const joshua = new Person('Joshua')
// Invoke sayHi() on "joshua" instance.
joshua.sayHi()
// Output:
// Person {name: "Joshua", sayHi: ƒ}
// Classes example no.3: with instantiation in strict mode (regular function, no binding)
// Switch to strict mode.
'use strict'
// Declare a class with public property and method.
class Person {
constructor(name) {
this.name = name
}
sayHi() {
console.log(this)
}
}
// Instantiate the Person class.
const joshua = new Person('Joshua')
// Invoke sayHi() on "joshua" instance.
joshua.sayHi()
// Output:
// Person {name: "Joshua"}
// Classes example no.4: with instantiation in strict mode (arrow function)
// Switch to strict mode.
'use strict'
// Declare a class with public property and method.
class Person {
constructor(name) {
this.name = name
}
sayHi = () => {
console.log(this)
}
}
// Instantiate the Person class.
const joshua = new Person('Joshua')
// Invoke sayHi() on "joshua" instance.
joshua.sayHi()
// Output:
// Person {
// sayHi: ƒ (),
// name: 'Joshua',
// __proto__: Person { constructor: ƒ Person() }
// }
// Classes example no.5: without instantiation in sloppy mode (regular function, no binding)
// Declare a class with static property and method.
class Person {
static name = 'Luke'
static sayHi() {
console.log(this)
console.log(this === Person)
}
}
// Invoke sayHi() method.
Person.sayHi()
// Output:
// class Person {
// static name = 'Luke'
// static sayHi() {
// console.log(this)
// console.log(this === Person)
// }
// }
// true
// Classes example no.6: without instantiation in sloppy mode (arrow function)
// Declare a class with static property and method.
class Person {
static name = 'Luke'
static sayHi = () => {
console.log(this)
console.log(this === Person)
}
}
// Invoke sayHi() method.
Person.sayHi()
// Output:
// class Person {
// static name = 'Luke'
// static sayHi = () => {
// console.log(this)
// console.log(this === Person)
// }
// }
// true
// Classes example no.7: without instantiation in strict mode (regular function, no binding)
// Switch to strict mode.
'use strict'
// Declare a class with static property and method.
class Person {
static name = 'Luke'
static sayHi() {
console.log(this)
console.log(this === Person)
}
}
// Invoke sayHi() method.
Person.sayHi()
// Output:
// class Person {
// static name = 'Luke'
// static sayHi() {
// console.log(this)
// console.log(this === Person)
// }
// }
// true
// Classes example no.8: without instantiation in strict mode (arrow function)
// Switch to strict mode.
'use strict'
// Declare a class with static property and method.
class Person {
static name = 'Luke'
static sayHi = () => {
console.log(this)
console.log(this === Person)
}
}
// Invoke sayHi() method.
Person.sayHi()
// Output:
// class Person {
// static name = 'Luke'
// static sayHi = () => {
// console.log(this)
// console.log(this === Person)
// }
// }
// true
Event listeners
When you use the this
keyword with event listeners, it will refer to the HTML element to which you attach the event listener. If you attach event listener to a button, this
will refer to that button element. That button will become value of this
. If you attach event listener to global window
object, this
will refer to the global window
object.
// Event listener example no.1: sloppy mode
// Find button in the DOM.
const btn = document.querySelector('.btn')
// Attach event listener to the button.
btn.addEventListener('click', function() {
console.log(this)
console.log(this === window)
})
// Output on click on the button:
// <button>Click me</button>
// false
// Arrow function example no.2: strict mode
// Switch to strict mode.
'use strict'
// Find button in the DOM.
const btn = document.querySelector('.btn')
// Attach event listener to the button.
btn.addEventListener('click', function() {
console.log(this)
console.log(this === window)
})
// Output on click on the button:
// <button>Click me</button>
// false
// Arrow function example no.3: event listener on window
// Attach event listener to the button.
window.addEventListener('click', function() {
console.log(this)
console.log(this === window)
})
// Output on click on the button:
// Window {0: Window, 1: Window, window: Window, self: Window, document: document, name: "", location: Location, …}
// true
Arrow functions
With arrow functions, this
keyword works differently than with regular functions. Arrow functions don't have their own this
. When you use this
in an arrow function it will inherit its value from its context. Context here is the context at which you defined that arrow function.
Global and local scope, this and arrow functions
If your arrow function is in a global scope, this
will refer to the global object window
. This is true for sloppy and strict mode. It is also true if the arrow function is inside a regular function, in a sloppy mode. If you are in a strict mode, and arrow function is inside a regular function, the value of this
will be undefined
.
// Arrow function example no.1: global function in a sloppy mode
// Declare an arrow function.
const foo = () => {
// Log the value of this.
console.log(this)
console.log(this === window)
}
// Invoke foo() and bar() functions.
foo()
// Output:
// Window {0: Window, 1: Window, window: Window, self: Window, document: document, name: "", location: Location, …}
// true
// Arrow function example no.2: global function in a strict mode
// Switch to strict mode.
'use strict'
// Declare a function.
const foo = () => {
// Log the value of this.
console.log(this)
console.log(this === window)
}
// Invoke foo() and bar() functions.
foo()
// Output:
// Window {0: Window, 1: Window, window: Window, self: Window, document: document, name: "", location: Location, …}
// true
// Arrow function example no.3: local function in a sloppy mode
// Declare a regular function.
function foo() {
// Return an arrow function.
return () => {
// Log the value of this.
console.log(this)
console.log(this === window)
}
}
// Invoke foo() and bar() functions.
foo()()
// Output:
// Window {0: Window, 1: Window, window: Window, self: Window, document: document, name: "", location: Location, …}
// true
// Arrow function example no.4: local function in a strict mode
// Switch to strict mode.
'use strict'
// Declare a regular function.
function foo() {
// Return an arrow function.
return () => {
// Log the value of this.
console.log(this)
console.log(this === window)
}
}
// Invoke foo() and bar() functions
foo()()
// Output:
// undefined
// false
Arrow IIFEs
When you use arrow function to create Immediately Invoked Function Expression (IIFE) this
will refer to global window
object. This applies to both, sloppy as well as strict mode.
// Arrow IIFE example no.1: sloppy mode
// Declare arrow IIFE.
(() => {
console.log(this)
console.log(this === window)
})()
// Output:
// Window {0: Window, 1: Window, window: Window, self: Window, document: document, name: "", location: Location, …}
// true
// Arrow IIFE example no.2: strict mode
// Switch to strict mode.
'use strict';
// Declare arrow IIFE.
(() => {
console.log(this)
console.log(this === window)
})()
// Output:
// Window {0: Window, 1: Window, window: Window, self: Window, document: document, name: "", location: Location, …}
// true
Objects, classes, this and arrow functions
If you declared your arrow function in an object, this
will refer to global object window
. In case of a class, it will refer to the class itself.
// Arrow function example no.5: object in sloppy mode
// Declare an object.
const obj = {
name: 'Luke',
sayHi: () => {
console.log(this)
console.log(this === window)
}
}
obj.sayHi()
// Output:
// Window {0: Window, 1: Window, window: Window, self: Window, document: document, name: "", location: Location, …}
// true
// Arrow function example no.6: object in strict mode
// Switch to strict mode.
'use strict'
// Declare a function
const obj = {
name: 'Luke',
sayHi: () => {
console.log(this)
console.log(this === window)
}
}
obj.sayHi()
// Output:
// Window {0: Window, 1: Window, window: Window, self: Window, document: document, name: "", location: Location, …}
// true
// Arrow function example no.7: class in sloppy mode
// Declare a class with static property and method.
class Person {
static name = 'Luke'
static sayHi = () => {
console.log(this)
console.log(this === Person)
}
}
Person.sayHi()
// Output:
// Luke()
// true
// Arrow function example no.8: class in strict mode
// Switch to strict mode.
'use strict'
// Declare a class with static property and method.
class Person {
static name = 'Luke'
static sayHi = () => {
console.log(this)
console.log(this === Person)
}
}
Person.sayHi()
// Output:
// Luke()
// true
Event listeners, this and arrow functions
If you use arrow function as a callback for event listener, this
will refer to global object window
. This will happen in both, sloppy and also strict mode.
// Arrow function example no.9: event listener in sloppy mode
// Find button in the DOM.
const btn = document.querySelector('.btn')
// Attach event listener to the button.
btn.addEventListener('click', () => {
console.log(this)
console.log(this === window)
})
// Output on click on the button:
// Window {0: Window, 1: Window, window: Window, self: Window, document: document, name: "", location: Location, …}
// true
// Arrow function example no.10: event listener in strict mode
// Switch to strict mode.
'use strict'
// Find button in the DOM.
const btn = document.querySelector('.btn')
// Attach event listener to the button.
btn.addEventListener('click', () => {
console.log(this)
console.log(this === window)
})
// Output on click on the button:
// Window {0: Window, 1: Window, window: Window, self: Window, document: document, name: "", location: Location, …}
// true
// Arrow function example no.11: event listener on window
// Attach event listener to the button.
window.addEventListener('click', () => {
console.log(this)
console.log(this === window)
})
// Output on click on the button:
// Window {0: Window, 1: Window, window: Window, self: Window, document: document, name: "", location: Location, …}
// true
Conclusion: A quick guide to this keyword in JavaScript
The this
keyword can be sometimes confusing and unpredictable. It is no wonder some JavaScript developers don't like to use it, and even discourage it. I hope that this tutorial helped you understand what this
keyword refers to in specific contexts.
Top comments (2)
Great post! I liked your approach of explaining how the this binding works based on either sloppy or strict mode.
By the way, I also wrote an article about “this” a few months ago, here’s the link in case you want to take a look: dev.to/diegolepore/what-s-the-bind...
My main focus in this article is explaining the “this” binding based on “where” and “how” a function is invoke, and how answering these two questions will lead us to the binding of “this” to a specific object. Understanding this gives us the ability to take advantage of this feature in our programs. It’s really cool 🙂
Cheers! 👋🏻
Thanks. About this. I wrote two articles about this topic as well:
blog.alexdevero.com/this-in-javasc...
blog.alexdevero.com/this-keyword-i...