‘this’ in Javascript

Objects are the basic building blocks in JavaScript. There’s one special object available in JavaScript, the this object. You can see the value of this at every line of JavaScript execution. The value of this is decided based on how the code is being executed.

Before getting started with this, we need to understand a little about the JavaScript runtime environment and how a JavaScript code is executed.

Scope vs Context

When approaching this for the first time, many developers presume that it works in a similar way to scope. But that thinking can lead to mistakes!

That’s because `this` depends on context, rather than scope…so what’s the difference?

What is Scope?

Scope controls the context in which variables are accessible. Here’s a classic example:

function foo() {
const bar = true;
return bar;
};
console.log(foo()); // true
console.log(bar); // ReferenceError: bar is not defined

The variable bar is only accessible inside our function, foo . If we call foo() , we’ll get the value of bar . But if we try to use bar outside of foo , we’ll get a ReferenceError . This is known as local scope or functional scope.

It’s tempting to imagine that this works in the same way. But this misunderstanding is probably the reason for most beginners’ mistakes!

What is Context?

To get an understanding of context, let’s re-write our function foo to set the value of this.bar :

function foo() {
this.bar = true;
return bar;
};
console.log(foo()); // true
console.log(bar); // true

Beginners often assume that, in the above example, this refers to the function foo . But when we try to access bar , we can!

That’s because the expression this.bar = true is actually writing a global variable bar . That’s because we haven’t set a specific context and so, as in the first example in this article, this refers to the global object. To give this a context, you need to use a method like call , apply or bind .

Thus, the object this refers to changes every time the execution context is changed.

`this` refresher

In Object Oriented JS we learned that in JS, everything is an object. Because everything is an object, we came to understand that we could set and access additional properties to functions.

Setting properties to a function and additional methods via the prototype is super awesome … but how do we access them?!??!

We were introduced to the this keyword. We learned that every function gets this property automatically.

But life isn’t perfect. Sometimes, we lose our this reference. When that happens, we end up using confusing hacks to save our reference to this. Check out this confusing hack from our localStorage exercise:

So, why did I need to save a this reference? Because inside deleteBtn.addEventListener, this refers to the deleteBtn object. This is unfortunate. Is there a better solution? YES….in such cases call(), apply() and bind() comes to the rescue.

“this” has different values depending on how is the function invoked instead of where is “this” taken from.

  • In a method, this refers to the owner object.
  • Alone, this refers to the global object.
  • In strict mode, when used alone, this also refers to the Global object [object Window]
"use strict";
var x = this; # [object Window]
  • In a regular function, this refers to the global object.
  • In a regular function, in strict mode, this is undefined.
  • In an event, this refers to the element that received the event.
  • Methods like call(), and apply() can refer this to any object.

In the example below, when calling person1.fullName with person2 as argument, this will refer to person2, even if it is a method of person1:

var person1 = {
fullName: function() {
return this.firstName + " " + this.lastName;
}
}
var person2 = {
firstName:"John",
lastName: "Doe",
}
person1.fullName.call(person2); // Will return "John Doe"

We know that windowis a global object in the browser so if we type thisin the console and it should return window object, which it does.

In node.js CLI, if you try doing the above you will get an object that will have all globally used function like console , process etc. (try once).

Note: The value of this keyword depends on the object the function is run/called /sit on. Therefore thiskeyword has different values depending on where it is used.

Note: From now, this and context is used interchangeably.

[1].Context — globally and inside a function.

foo is the function is defined at the global level and is called on global level object i.e windowso calling fooand window.foois same. Hence the context is a window object.

Whereas if we do new foo() at the global level then will get this as fooobject, as below:

Note: new operator creates an instance of an object. Context of the function will be set to the created instance of an object.

[2].Context — under 2nd level function.

[3]. Context — when the function is defined globally and used under an object (Implicit Binding).

Note: From above, we get that value of this keyword depends on the function is called upon not where the function is defined.

source: https://medium.com/@happymishra66/this-in-javascript-8e8d4cd3930

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. You can change this context through .call(), .apply() and .bind(). Value of this is equal to the value of the object which invokes the function. this is not assigned a value until an object invokes the function where this is defined.

Global Context

When functions are executed in the global scope, value of this is window object. This is because when we call a function in global scope by default they are invoked on the Window object. In strict mode, value of this in the global context will be undefined. Consider the below example:

var myFunction = function(){
console.log(this);
console.log(this=== window);
}

myFunction();
// Output: Window object. In strict mode value will be undefined

The above function was not executed inside any other function or object hence, by default myFunction was called on the global object.

myFunction() is equivalent to window.myFuntion()

Hence the value of this is ‘window’. In strict mode, value of this would be undefined.

As an object method

When a function is called as a method of an object, it’s this is set to the object the method is called on.

Example:

var val = 37;
var myObj = {
val : 10,
someFunction : function(){
console.log(this.val);
//Output: 10 since the value of this is equal to myObj
console.log(window.val); //Output: 37
console.log(this === myObj) // true
console.log(this)//Output: myObj object
}
}

myObj.someFunction();

In the above example, we have defined two val variables, one in the global scope with value 37 and another inside myObj object with value 10.

When we call myObj.someFunction(), as someFunction() was called by myObj object, value of this inside someFunction will become equal to myObj.

Hence, inside someFunction when we do console.log(this.val), it outputs myObj’s val variable value i.e 10.

When we do window.val, we get value 37 as global value for val is 37.

Another example:

//Variable defined in global scope
var val = 37;

var myObj = {
val : 10
}

var someFunction = function(){
console.log(this.val);
console.log(window.val);
console.log(this === myObj);
console.log(this);
console.log(this === window)
}

myObj.objectFunc = someFunction;
myObj.objectFunc();

/*
Output:
1. 10
2. 37
3. true
4. myObj
5. false
*/

someFunction();
/*
Output:
1. 37
2. 37
3. false
4. window
5. true
*/

In the above example, we have defined someFunction outside myObj object.

First we call someFunction() on myObj object, hence inside someFunction value of this is equal to myObj object.

In second case, we have called someFunction() in the global scope which is same as writing window.someFunction(). Here, as someFunction() has been called on window object, value of this is equal to window object.

First we call someFunction() in the context of myObj. Later we called the function in the global context and the value of this inside the someFunction() changed accordingly. This shows that the value of this was determined dynamically on the basis of execution context.

As a constructor

When a function is used as a constructor (with the new keyword), its this is bound to the new object being constructed. To understand what constructor function are, please go through this article.

function ConstructorFunc(value){
this.someValue = value;
}

var obj1 = new ConstructorFunction(20);
console.log(obj1.someValue)
//Output: 20

Here, we have defined ConstructorFunc to create new objects. When

var obj1 = new ConstructorFunction(20) is executed, value of this will be equal to the new object that is created.

‘this’ inside an IIFE

In IIFE, value of this is always equal to Window object. Why?

As, IIFE is self-invoked, it has not been called by any object. Hence, the value of this inside IIFE is Window object.

Let’s see an example:

// IIFE outside any function 
(function() {
console.log(this); // Output: Window object
})()


// IIFE inside an object function
var obj = {};

var someFunc = function() {
console.log("Functions this");
console.log(this === obj); // true
console.log('++++++++++++++++++++++++++');

// IIFE
(function() {
console.log("IIFE this");
console.log(this); // Output: Window object
console.log("IIFE");
})()
};

obj.func = someFunc;

obj.func();

Console Output:

First example:

In the first example, IIFE outside any function, value of this inside IIFE will be Window object.

Second Example:

In the second example, when we have called IIFE inside someFunc still the value of this is Window object not obj object.

This is because, value of this inside a function is equal to the object on which it is called. someFunc is called on obj, hence value of this inside someFunc is obj. But, IIFE is self-invoked, it has not been called by any object. Hence, the value of this inside IIFE is Window object.

Event handler in JavaScript

Inside event handler, value of this is equal to the element on which the event is fired. Let’s see this with an example of click event.

<!DOCTYPE html>
<html>
<head>
<title></title>
</head>
<body>
<div id="divId">Hello</div>
<script type="text/javascript">
var id = document.getElementById('divId').addEventListener('click', clickMe, false);

function clickMe(event) {
console.log(event.currentTarget);
console.log("CLick Me");
console.log(this);
}
</script>
</body>
</html>

In the above example, we have added an on click event handler on the div element which calls the clickMe function.

When we click on the div, from the above console output we can see that value of this is equal to the div element which we clicked.

We can change the value of this at run time using call, apply and bind function. We will discuss call, apply and bind in another article.

“this” inside arrow functions

this.robot = "global";
const thisRobots = {
robot: "local_1",
anotherRobotName: function (robot = "new_local") {
return this.robot;
},
details: {
robot: "local_2",
robotName: function () {
return this.robot;
},
arrowrobotName: () => this.robot
}
};
console.log(thisRobots.details.robotName());
console.log(thisRobots.details.arrowrobotName());
console.log(thisRobots.anotherRobotName());
# local_2
# global
# local_1

Examples:

const func = () => { return this };
let obj = {func, a: 10}
obj.func(); # window

We will always get the global window object here coz of arrow functions.

'this’ cannot be changed by using call, apply or bind. If you need to change a binding, use a regular function.

const a = () => {
return this;
}
a() === window;
# true

source: youtube/techsith

◉ “this” in global scope

this.name = "RSSB";
console.log(window.name); # anil
// this is a public property of window means accessible from outsidethis.name = {
firstname: "anil"
}
this.name.firstname; # anil
ORwindow.name.firstname; # anil

◉ “this” inside node.js

Not every JavaScript program runs in a browser. You should be aware that, in non-windowed environments, the global meaning of this won’t be the window object — because this doesn’t exist!

Note that, when used globally in Node.js, this represents an empty object {}:

console.log(this);    // {}
this.foo = 'bar' ;
console.log(this); // { foo: 'bar' }

◉ `this` inside an object

let name = {
firstname: "anil"
}
name.firstname; # anil
this.name.firstname; # TypeError: cannot read property of undefined

◉ `this` inside a method

let name = {
firstname: "anil",
getFullName: function(){
return this.firstname;
}
};
console.log(name.getFullName()); # anil

◉ `this` inside a function (outside of an object):

this.name = "RSSB";
const getFullName= function(){
return this.name;
}
getFullName();
# RSSB
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
"use strict"
this.name = "RSSB";
const getFullName= function(){
return this.name;
}
getFullName();
# undefined
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

"call" to the rescue for above
"use strict";
this.name = "RSSB";
const getFullName= function(arg){
return this.name + arg;
}
getFullName.call(this, "to all"); # RSSB to all

◉ `this` inside a nested function

◉ `this` inside classes

Using Bind in Class Methods

If you’re used to a framework like React, which makes heavy use of JavaScript classes, you’ll likely be used to binding your methods inside your class’s constructor method:

import React from 'react';  class Counter extends React.Component { 
constructor(props) {
super(props);
this.state = { count: 0 };
this.addOne = this.addOne.bind(this);
};
addOne(event){
this.setState({ count: this.state.count + 1 });
};

render(){
return (
<button type="button" onClick={this.addOne}>
Click Me
</button>
);
};
};

The reason for the longwinded expression this.addOne = this.addOne.bind(this) is that we always want the addOne method to be executed in the context of the current React class. Otherwise, our value of this will not be what we expect.

React classes run in ‘strict mode’, so instead of this defaulting to window , it returnsundefined: our addOne method would attempt to use undefined.setState , which — of course — doesn’t exist!

Using the bind method means that, whenever we call addOne , it will use the setState method that is part of our class.

Implicit Binding with Arrow Functions

More experienced React developers might prefer to avoid writing out the bind expression with every new method. Instead, the Counter component above could be re-written like so:

import React from 'react';class Counter extends React.Component { 
state = { count: 0 };
addOne = (event) => {
this.setState({ count: this.state.count + 1 });
};

render(){
return (
<button type="button" onClick={this.addOne}>
Click Me
</button>
);
};
};

This works because the arrow function automatically adopts the this binding from the enclosing scope — in this class, Counter .

JavaScript ‘this’ in Regular, Arrow functions and Methods — a Short Circuit Example

To start, it is worth noting how outside of any function this points to what is referred as the global object. Consider this example:

this.robot = "Hal 9000";

Try console.log(this.robot) what you get? `Hall 9000` of course.

MDN Documentation explains how this can be determined by where and how a function is called. There are nuances in strict mode but we will omit them for brevity of this article. With that in mind, lets consider this function:

function robotName(){
console.log(this.robot)
}

Calling robotName() will give you an error? Well not really, it will give you Hall 9000 again. Why? Because in a regular function context, this defaults to the global object (unless we specify otherwise).

Let’s do that:

function robotName() {  
this.robot = "Astro Boy";
console.log(this.robot)
}
// => Astro Boy

So when we call robotName(), what do we get? Astro Boy!

Let’s get make things a bit more complex. Consider this:

thisRobots.details.robotName(); 
# Astro Boy

robotName()is in the context of the details object. Now, what if we called

thisRobots.details.arrowrobotName();
# Hall 9000

Surprised? Well this is a main distinction of arrow functions vs regular functions is that in arrow functions `this will retain the value of its enclosing context. Since it will be determined by its surrounding scope, in our case, is the global context, so again `this` will be the territory of Hall 9000. this in arrow functions is always inherited from their surrounded scope, it doesn’t have scope of its own like regular functions.

thisRobots.anotherRobotName();  # calling without arguments
# Johnny 5
!

Why?? Well anotherRobotName() method is defined inside thisRobotswhich is an object.

When we call a method in an object, this is bound to its surrounding object, in this case thisRobots object.

◉ `this` exercises

function func() {
return this;
};
func(); # global window object
# But there are three methods we can use to change the meaning of this when we call it: call , apply and bind .# Say we wanted this to represent the string 'Hello World!' , we can do that in a number of ways:func.call('Hello World');
func.apply('Hello World');
func.bind('Hello World')();
# Each line of the code above would return the string 'Hello World!'const a = 1;
const obj = { a: 2 };
function whatIsA() { return this.a };

Whether whatIsA() returns 1 or 2 will depend on how we call it:

whatIsA();            // 1
whatIsA(obj); // 1
whatIsA.call(obj); // 2
whatIsA.apply(obj); // 2
whatIsA.bind(obj)(); // 2
var x = "global";
const foo= {
x: 10,
getX: function () {
return this.x;
}
};
let y = foo.getX;
console.log(y()); # global

If we call y , what’s will the result be? Without any specific context, this will take the value of x in the global context. In this case, there isn’t one, so we’ll get undefined .

But we can bind our function y to the context of foo :

const foo = {
x: 10,
getX: function () {
return this.x;
}
};
let y = foo.getX;
y = y.bind(foo); or y.bind(foo)();

Now, whenever we call y , we’ll get the number 10 . Pretty useful!

References:

Must Reads @ https://medium.com/better-programming/understanding-the-this-keyword-in-javascript-cb76d4c7c5e8

Experience with Front-end Technologies and MERN / MEAN Stack. Working on all Major UI Frameworks like React, Angular.