This article will help you fully understand the keyword this
in javascript. With some “pain-in-the-ass” examples, I’ll show you how to turn this
from a “headache” into a real helper.
# “this” is a changeful object
Maybe you misunderstood this
keyword with a class
this
. But javascript this
keyword behaves a bit different than some other programming languages like Python or Java. The way to use it is pretty similar and even behaves the same in some scenarios.
But in javascript, this
keyword’s action scope can actually change. Right, no joking, it changes. And this is probably the reason why it brings us a lot of headaches while using it in our project.
According to w3schools and MDN Web Docs,
“this” is a property of an execution context. It refers to the object it belongs to.
It sounds a little ambiguous.
Yet, they can be interperted as:
this
is a camera-monitor. Put it in your house, you can monitor everything viathis
. If you put it elsewhere, the picture certainly changes.
I guess now you can see the good adaptiveness from the keyword this
.
Okay, let’s take a look at how this
varies in our real world programs.
# Some Confusing Examples
Open your browser console, and input some of the following examples. You’ll personally understand the confusing part about this
keyword in different scenarios.
# 1. “this” is window
// 1. global console
console.log(this) // window
// 2. arrow function
var thisIsWindow = () => {
console.log(this) // window
}
// 3. normal function
function thisIsWindow () {
console.log(this) // window
}
// 4. immediate function
(function () {
console.log(this) // window
})()
~function () {
'use strict'
console.log(this) //window
}()
// 5. function call inside another function
function another () {
thisIsWindow() // window
}
// 6. arrow function call inside an object
var obj = {
func: () => {
console.log(this) // window
}
}
// 7. normal function call inside an object function
var obj = {
func: function () {
thisIsWindow() // window
}
}
# 2. “this” is NOT window
// 1. normal object function
var obj = {
func: function () {
console.log(this) // obj
}
}
// 2. immediate function under strict mode
(function () {
'use strict'
console.log(this) // undefined
})()
~function () {
'use strict'
console.log(this) // undefined
}() // undefined
// 3. bind DOM event to a function
document.body.onclick = function () {
console.log(this) // document.body
}
document.body.addEventListener("click", function () {
console.log(this) // document.body
})
There are more complex examples that will lead to an unexpected context of this
keyword. I won’t be listing all of them out here. I think you’ve already felt the painful part of it and start to perceive this
keyword’s as a significant knowledge point since it may confuse you anytime at the beginning.
Don’t worry, let me explain you the key points that needs special attentions so that you won’t make mistakes with this
during the development.
# Matter of “this” fact
#
1. As for functions, if a function is chained by another object. this
refers to the owner object. If function is not chained, this
refers to window object
function func () {
console.log("this: ", this)
}
var obj = {
func: func
}
obj.func() // this: {func: function}
#
2. this
within an immediate function always refers to window object
(function(){
console.log("this: ", this) // this: Window {...}
})()
~function(){
console.log("this: ", this) // this: Window {...}
}()
#
3. While binding an event to a DOM element, this
refers to the current element
document.body.onclick = function () {
console.log("this: ", this) // this: <body>...</body>
}
#
4. In a constructor function, this
refers to the function/class instance
// Function
function Website (name, url) {
this.name = name
this.url = url
this.print = function () {
console.log(this.name + ' -- ' + this.url)
}
}
// Class
class Website {
constructor (name, url) {
this.name = name
this.url = url
}
print () {
console.log(this.name + ' -- ' + this.url)
}
}
var pitayanBlog = new Website('Pitayan Blog', 'https://pitayan.com')
pitayanBlog.print() // PitayanBlog -- https://pitayan.com
Note: The console
output will change its value in terms with the caller’s context.
var test = pitayanBlog.print
test() // undefined -- undefined
#
5. Change this
context scope with bind
bind
will help return a new function containing the specified context. Execute the returned new function will output the result.
var website = {
url: 'https://pitayan.com'
}
function func () {
console.log(this.url)
}
var newFunc = func.bind(website)
newFunc() // https://pitayan.com
#
6. Change this
context scope with apply
and call
In the following example, if you execute print
function directly it will output undefined
. But if you utilize apply
and call
to change the context scope of print
function, it will output “https://pitayan.com”.
var website = {
url: 'https://pitayan.com'
}
function print () {
console.log(this.url)
}
print() // undefined
print.apply(website)
// or
print.call(website)
#
7. The “strict mode” apply
/call
behave differently than “none strict mode”
function func () {
console.log("this: ", this)
}
// none strict mode
func.call() // this: Window {...}
func.call(null) // this: Window {...}
func.call(undefined) // this: window {...}
// strict mode
func.call() // this: undefined
func.call(null) // this: null
func.call(undefined) // this: undefined
Note: apply
behaves the same to call
in the above situation.
#
8. this
used within an arrow function always refers to the object where it’s defined
var obj = {
func: function () {
document.body.onclick = () => {
console.log("this: ", this) // this: {func: Function}
}
}
}
Here is something intersting about arrow function. Arrow function has no action scope for this
keyword, so if you use this
keyword within the arrow function this
refers to some object way up to the top layer.
var obj = {
func: function () {
return () => {
return () => {
console.log("this: ", this)
}
}
}
}
obj.func()()() // this: {func: Function}
Note: arrow function cannot use this
context, so it will ignore the first argument while invoking with apply
or call
.
var obj = {
name: 'obj',
func: function () {
var fn = () => {
console.log(this.name)
}
fn.call({ name: "something else" })
}
}
obj.func() // obj
Well, this is pretty much all of what you need to pay attention to while using javascript this object. Hope you’ve understood its usage and felt no longer confused using it.
Thanks for reading!
Here are some reference links: