this
keyword must be one of the most confusing JavaScript concepts due to its dynamic nature of how it's invoked. If you find yourself reading this article, you probably have come across this
several times and want to have a better understanding. I hope to make this
crystal clear with practical examples and minimal jargon. Make sure you open up your console in your favorite browser and follow along!
this
as global
The most straightforward way to identify this
is when it's used as a global object. A global object is an object which can be accessed from anywhere in your JavaScript code. Browsers call this global object window
and NodeJS call it global
. This basic default binding is called default binding.
console.log(this) // window
console.log(window) // window
console.log(this === window) // true
Did you know fetch
and localStorage
are part of the global window object?
Variables declared with var
keyword and function declarations become properties of the window object. The properties of the global object can be accessed without dot or bracket notation. However, variables declared using let
or const
keywords don't become part of the global object, instead they will be stored inside an inaccessible environment.
var age = 29
console.log(age) // 29
console.log(this.age) // 29
console.log(window.age) // 29
function sayHi() {
console.log("Hi")
}
sayHi() // Hi
this.sayHi() // Hi
window.sayHi() // Hi
const sayHello = function() {
console.log("Hello")
}
sayHello() // Hello
this.sayHello() // Uncaught TypeError: this.sayHello is not a function
window.sayHello() // Uncaught TypeError: window.sayHello is not a function
this
in functions
this
inside regular functions refer to the global object as well. Alternatively, we can also say that the context of these functions is the global object. Context simply means the value of this
at a given moment when your code is being run by the javascript engine (This is also known as the 'execution context').
var whatIsThis = function() {
console.log(this)
}
whatIsThis() // window
Word of caution: when use strict mode is used, it won't allow the default binding of this
to the window
object. Therefore, the value of this
results in undefined.
"use strict"
var whatIsThis = function() {
console.log(this)
}
whatIsThis() // undefined
this
in methods
Method means it's a function inside an object. this
keyword inside methods is set to its parent object. This is called implicit binding because this
is bound indirectly to the object it belongs to.
var obj = {
getThis: function() {
return this
},
}
// equivalent ES6 method
var obj = {
getThis() {
return this
},
}
console.log(obj.getThis()) // obj
console.log(obj === obj.getThis()) // true
To access properties of the object inside your methods, you will need to explicitly use this
. Otherwise, it will look for the variables with the same name inside the same function scope.
var me = {
name: "Phillip",
getName() {
const name = "Sunnie"
console.log("My name is " + this.name)
console.log("My name is " + name)
},
}
me.getName() // My name is Phillip
// My name is Sunnie
me.getName()
gives expected strings. What if we assign the definition of our getName method to a variable outside the method? This will cause loss of implicit binding of this
because the new getName function is no longer bound to the 'me' object. Instead, because our new getName is declared with var
keyword, it's bound to the global window object and will try to search this.name
as a property of the global object. Here is what official MDN doc says about this matter:
In most cases, the value of this is determined by how a function is called. It can't be set by assignment during execution, and it may be different each time the function is called.
var me = {
name: "Phillip",
getName: function() {
console.log("My name is " + this.name)
},
}
var getName = me.getName
me.getName() // My name is Phillip
getName() // My name is undefined
Instead of seeing 'My name is undefined', you might get 'My name is '. That's because we previously used this.name
globally so its key is there but its value got set to an empty string
How about we extract the getName method out of the 'me' object and make it a standalone function. Then create another same-named getName property inside the 'me' object and assign the standalone getName function as a reference. Let's try calling them separately. If we call the standalone function by itself, as you observed previously, this
will refer to the global object and tries to search the name from window
object. If you call the function as a property of the 'me' object, the context of this
will be the 'me' object.
function getName() {
console.log("My name is " + this.name)
}
var me = {
name: "Phillip",
getName: getName,
}
getName() // My name is undefined
me.getName() // My name is Phillip
Rule of thumb: Look at the left side of your method which it's called, this
belongs to that object. If there isn't any, this
belongs to the global object.
this
using call, apply and bind.
We want to make our 'getName' function more reusable. Let's improve our code by using call, apply and bind functions. These are special functions that append to function definitions and directly invoke them. call
and apply
take objects as the first argument thus the methods will understand how to handle this
. If no argument is passed, the context will be the global object.
function getName() {
console.log("My name is " + this.name)
}
var me = {
name: "Phillip",
}
var you = {
name: "Sunnie"
}
getName.call(me) // My name is Phillip
getName.apply(you) // My name is Sunnie
getName.call() // My name is undefined
The difference between call
and apply
is how you can pass in several arguments to the methods after the first argument. call
will separate the values by commas and apply
will also separate the values by commas but inside an array.
function getInfo(age, hobby) {
console.log(`My name is ${this.name}, I am ${age} and my hobby is ${hobby}`)
}
var me = {
name: "Phillip",
}
var you = {
name: "Sunnie"
}
getInfo.call(me, 29, "coding") // My name is Phillip, I am 29 and my hobby is coding
getInfo.apply(you, [28, "floral design"]) // My name is Sunnie, I am 28 and my hobby is floral design
Helpful tip: Comma takes in commas and Apply takes in an array
Often, we want to only associate certain methods with certain objects. bind
helps us link a specific method to a specific object so that the value of this
is predictable and can be found out by looking at its definition instead of investigating how it's invoked. Unlike call and apply, bind won't immediately invoke its attached function. This is called explicit binding
function getName() {
console.log("My name is " + this.name)
}
var me = {
name: "Phillip",
}
getName = getName.bind(me)
getName() // My name is Phillip
Don't forget to reassign it back to the method after you use bind!
The practical use of bind is when a function is passed as a callback. Let's look at one example without the use of bind.
var me = {
name: "Phillip",
getName: function() {
console.log("My name is " + this.name)
},
}
function calleMeMaybe(callback) {
callback()
}
calleMeMaybe(me.getName) // My name is undefined
getName is undefined because, under the hood, this is what happens.
callback = me.getName
Let's now bind getName to the 'me' object.
var me = {
name: "Phillip",
getName: function() {
console.log("My name is " + this.name)
},
}
me.getName = me.getName.bind(me)
function calleMeMaybe(callback) {
callback()
}
calleMeMaybe(me.getName) // My name Phillip
this
in function constructors
In JavaScript, functions can serve as constructors to build new objects using the "new" keyword. this
will be set to an instance (or an object) that is created by the function constructor.
function Song(author) {
this.author = author
this.song = "Let it go"
this.getInfo = function() {
console.log(`${this.author} sang ${this.song}`)
}
}
var song = new Song("Idina Menzel")
song.getInfo() // Idina Menzel sang Let it go
var song1 = new Song("Demi Lovato")
song1.getInfo() // Demi Lovato sang Let it go
// change of context
var getInfo = song1.getInfo
getInfo() // undefined is sung by undefined
this
with classes
Classes are modern function constructors. Inside classes, this
will behave identically as the function constructors and will refer to particular objects that are created by the classes. Notice that "strict mode" is applied to classes by default.
class Song {
constructor(author) {
this.author = author
this.song = "Let it go"
}
getInfo() {
console.log(`${this.song} is sung by ${this.author}`)
}
}
const song = new Song("Idina Menzel")
song.getInfo() // Idina Menzel sang Let it go
const song1 = new Song("Demi Lovato")
song1.getInfo() // Demi Lovato sang Let it go
// change of context
const getInfo = song1.getInfo
getInfo() // Uncaught TypeError: Cannot read property 'song' of undefined
If you are familiar with React, you will notice we explicitly bind event handlers with the class itself. That is because event handler methods are passed as callbacks by some event listeners like onClick, onSubmit, etc... Remember, the callback functions lose their context.
class Form extends React.Component {
constructor(props) {
super(props)
this.handleClick = this.handleClick.bind(this) // necessary
}
handleSubmit(event) {
// Handle logic
}
render() {
return <button onClick={this.handleSubmit}>Submit</button>
}
}
this
in arrow functions
JavaScript can get quirky and cause unexpected behaviors. What do you think the value of this
will be in a function inside of a method? Our intuition tells us it will still refer to the parent object that the method belongs to. However, it doesn't. this
actually will refer to the window
object. Let's take our prior example and modify it.
var me = {
name: "Phillip",
getName: function () {
function innerFunction() {
console.log("My name is " + this.name)
}
innerFunction();
},
}
me.getName() // My name is undefined
There are multiple ways to fix this problem.
- We can store
this
to a variable and reference the variable in the inner function. By convention, this variable is called 'self'. - We can use
bind
inside the method to connect the inner function to the method's context. - Or use the arrow function.
In arrow functions,
this
retains the value of the enclosing lexical context'sthis
. - MDN
It means that the value of this
is set to the function that contains the arrow function.
// 1
var me = {
name: "Phillip",
getName: function () {
var self = this;
function innerFunction() {
console.log("My name is " + self.name)
}
innerFunction();
},
}
me.getName()
// 2
var me = {
name: "Phillip",
getName: function () {
function innerFunction() {
console.log("My name is " + this.name)
}
innerFunction = innerFunction.bind(this);
innerFunction();
},
}
me.getName()
//3
var me = {
name: "Phillip",
getName: function () {
const innerFunction = () => {
console.log("My name is " + this.name)
}
innerFunction();
},
}
me.getName()
this
with HTML
JavaScript event listeners get access to this
when an event has been triggered. this
then will refer to the HTML element that caused it. If the event listener callback function is declared as an arrow function, this
will refer to the window object, its enclosing context.
<h1 class="h1">Hello World</h1>
<h2 class="h2">Hi World</h2>
const h1 = document.querySelector(".h1")
const h2 = document.querySelector(".h2")
h1.addEventListener("click", function(e) {
console.log(e.target) // <h1 class="h1">Hello World</h1>
console.log(this) // <h1 class="h1">Hello World</h1>
})
h2.addEventListener("click", e => {
console.log(e.target) // <h2 class="h2">Hi World</h2>
console.log(this) // window
})
Summary
Thank you for reading my article! 👏👏 I sincerely hope that it was helpful content to demystify any confusion you had with this
keyword. I will leave with a summary of my lengthy article. Thanks again!
-
this
generally refers to the global object by default and in plain functions: default binding. - in strict mode,
this
is undefined. - Inside methods,
this
is the object which owns the method, but it depends on howthis
is invoked. Look at the left side ofthis
to determine its value. - Use call, apply to explicitly call the methods with desired objects. Use bind to glue together
this
to a specific object. - In Arrow functions, look at the enclosing context to determine the value of
this
Top comments (4)
Excellent article Phillip. When I was getting into JavaScript, I read an article somewhere that mentioned that 'this' is used to refer to the antecedent in its 'context', just like English(or any other languages that use pronoun). Thinking this way made so much easier to code in JavaScript. Hope this helps.
Thanks Jake! that is an useful way of thinking about how 'this' works! Nice tip :)
Some comments may only be visible to logged-in visitors. Sign in to view all comments.