this
is a keyword in JavaScript that refers to the current execution context or the object that a function is being executed within. It allows you to access and manipulate properties and methods within that context.
While that
is a keyword that is commonly used as a variable that serve as workarounds to preserve the value of this
in certain situations, especially when dealing with nested or callback functions, where the value of this
might refer to a different object or be undefined.
this
Keyword:this
is a special keyword in JavaScript that refers to the current execution context or the object that the function is being executed within.
The value of this
is determined dynamically at runtime, based on how a function is invoked.
this
provides a way to access and manipulate properties and methods within the current execution context.
In simple term, when you enter a building, what wraps you up is the building because you are inside the building.
Now, when you enter a room inside the building, what wraps you up is not the building, but the room that you entered.
How is this related to the
this
keyword? The building can be thought of as an object or a function, and you (the person), inside the building (i.e., object or function) is representing thethis
keyword.So now as you entered a room, you are not directly enclosed by the building (i.e., object or function) rather you are enclosed by a new room (i.e., another object or function) hence your context or the
this
keyword context changes.
The value of this
can change depending on the way a function is called:
Global Scope – When this
is used in the global scope (outside any function), it refers to the global object, which is window
in browsers and global
in Node.js.
Object Method – When this
is used inside a method of an object, it refers to the object itself. It allows the method to access and manipulate the object’s properties and methods.
const person = {
name: "John",
greet: function () {
console.log("Hello, " + this.name);
},
};
person.greet(); // Output: Hello, John
In the code example above, this
inside the greet
method refers to the person
object, so this.name
accesses the name
property of the object – name: “John”
.
Event Handlers –When this
is used within an event handler, such as a click event or a timer function e.g., (setTimeout), it usually refers to the element that triggered the event.
const button = document.querySelector("#myButton");
button.addEventListener("click", function () {
console.log("Button clicked:", this);
});
In this case, this
refers to the button
element, as it is the object that triggered the click event.
Explicit Binding – JavaScript provides methods that allow us to explicitly set the value of this
using functions such as call()
, apply()
, and bind()
.
function greet() {
console.log("Hello, " + this.name);
}
const person = { name: "John" };
greet.call(person); // Output: Hello, John
In this code example, greet()
is a function on its own and person
is an object on its own.
In order to use the name in the person
object inside the greet()
function, call()
is used to invoke the greet
function with person
as the explicit context for this
.
Note:
The behavior of
this
can be different in arrow functions, as they do not bind their ownthis
value, but rather inherit it from the surrounding lexical scope.
Regular functions in JavaScript have their own this
value, which is determined by how the function is called. It can change depending on the context or the way the function is invoked.
In arrow functions, the value of this
is not determined by how the function is called, but rather by the surrounding (lexical) scope.
This means that this
inside an arrow function refers to the same this
value as the enclosing scope where the arrow function is defined.
Let’s see an example to illustrate this behavior:
const person = {
name: "John",
sayHello: function () {
setTimeout(function () {
console.log("Hello, " + this.name);
}, 1000);
},
sayHelloArrow: function () {
setTimeout(() => {
console.log("Hello, " + this.name);
}, 1000);
},
};
person.sayHello(); // Output: Hello, undefined
person.sayHelloArrow(); // Output: Hello, John
In the code example above, we have an object called “person” with two methods: “sayHello” and “sayHelloArrow”. Both methods use a setTimeout
function to delay the execution of an inner function.
In the “sayHello” method, we use a regular function as the inner function of setTimeout
.
But, since regular functions have their own this
value, the this
inside the inner function (i.e., the function inside the setTimeout()
) refers to the global object (or undefined in strict mode) – which is the sayHello method rather than the “person” object.
Remember the building analogy we gave previously.
This means that
sayHello
method is the room that covers the function.While the
person
object is the building that covers the sayHello (the room).
Hence, when we try to access “this.name”, it results in “undefined”.
On the other hand, in the “sayHelloArrow” method, we use an arrow function as the inner function of setTimeout
.
The arrow function does not have its own this
value and instead inherits the this
value from the surrounding (lexical) scope, which is the “person” object.
Therefore, when we access “this.name” inside the arrow function, it correctly refers to the “name” property of the “person” object, resulting in the expected output “Hello, John”
.
Arrow functions in JavaScript provide a more convenient and predictable way to access the
this
value. By inheriting thethis
value from the surrounding scope, arrow functions eliminate the need to use workarounds like creating a separate variable or using functions likebind()
to maintain the desiredthis
context.
that
Keyword:that
is just a keyword commonly used as variables within JavaScript functions as a workaround to preserve the value of this
in certain scenarios.
This workaround is often used in nested functions or callback functions, where this
might refer to a different object, context or is undefined.
Here is a code snippet to illustrate the that
keyword:
const person = {
name: "John",
greet: function () {
const that = this;
setTimeout(function () {
console.log("Hello, " + that.name);
}, 1000);
},
};
person.greet(); // Output: Hello, John
In this example, the greet
method of the person
object uses the variable that
to preserve the value of this
within the nested callback function of “setTimeout”.
Without using that
, this
would refer to the global object (or undefined in strict mode) which is the function above it – the greet
method instead of the person
object.
It’s important to note that the choice between using this
or that
depends on the specific context and requirements of the code.
Generally, this
is preferred when it correctly refers to the desired object, while that
is used as a workaround when this
needs to be preserved in nested or callback functions.