This keyword with Arrow Functions => Simple & Code Examples
When using traditional function syntax, the value of "this" inside the function is determined by how the function is called, such as through an object method invocation or as a standalone function.
However, when using arrow functions, the value of "this" is determined lexically, based on the surrounding context in which the arrow function is defined. This means that the arrow function captures the value of "this" from its enclosing scope, rather than from the function or method in which it is called.
Example in JavaScript:
const person = {
name: 'Esther',
greet: function() {
console.log(`Hello, my name is ${this.name}.`);
}
};
person.greet(); // Output: "Hello, my name is Esther."
const greetFunction = person.greet;
greetFunction(); // Output: "Hello, my name is undefined."
const arrowFunction = () => {
console.log(`Hello, my name is ${this.name}.`);
};
arrowFunction(); // Output: "Hello, my name is undefined."
The arrow function is defined outside of any function or object, so it has no surrounding context to capture this
from. In strict mode, the value of this
inside the arrow function will be undefined
. In non-strict mode, the value of this
inside the arrow function will be the global object (window
in a browser, or global
in Node.js).
Here's the same example in TypeScript:
interface Person {
name: string;
greet: () => void;
}
const person: Person = {
name: 'Esther',
greet: function(this: Person) {
console.log(`Hello, my name is ${this.name}.`);
}
};
person.greet(); // Output: "Hello, my name is Esther."
const greetFunction: () => void = person.greet;
greetFunction(); // Output: "Hello, my name is undefined."
const arrowFunction: () => void = () => {
console.log(`Hello, my name is ${this.name}.`);
};
arrowFunction(); // Output: "Hello, my name is undefined."
In this example, the arrow function is also defined outside of any function or object, and there is no type annotation to specify the expected this
type. When calling the arrow function, the value of this
is not specified, so it defaults to undefined
.
In both JS and TS code examples, the output of the arrow function is undefined
because arrow functions capture this
from their surrounding context, rather than having their own this
binding like traditional functions.
What can be done
To fix the issue and have the arrow function output the correct value, you can use a closure to capture this
from the surrounding context and pass it as an argument to the arrow function, like so:
JavaScript:
const person = {
name: 'Esther',
greet: function() {
console.log(`Hello, my name is ${this.name}.`);
}
};
person.greet(); // Output: "Hello, my name is Esther."
const greetFunction = person.greet;
greetFunction(); // Output: "Hello, my name is undefined."
const arrowFunction = (self) => {
console.log(`Hello, my name is ${self.name}.`);
};
arrowFunction(person); // Output: "Hello, my name is Esther."
TypeScript
interface Person {
name: string;
greet: () => void;
}
const person: Person = {
name: 'Esther',
greet: function(this: Person) {
console.log(`Hello, my name is ${this.name}.`);
}
};
person.greet(); // Output: "Hello, my name is Esther."
const greetFunction: () => void = person.greet;
greetFunction(); // Output: "Hello, my name is undefined."
const arrowFunction: (self: Person) => void = (self) => {
console.log(`Hello, my name is ${self.name}.`);
};
arrowFunction(person); // Output: "Hello, my name is Esther."
In this example, we define the arrow function to take an argument named self
, which is used inside the function to access the name
property. When we call the arrow function and pass the person
object as the self
argument, the arrow function can correctly output the value of this.name
.
In JavaScript and TypeScript, arrow functions do not have their own this
binding, so they capture this
from their surrounding context. When an arrow function is defined outside of any function or object, its surrounding context is the global object, which can lead to unexpected behavior.
To work around this issue, you can use a closure to capture this
from the surrounding context and pass it as an argument to the arrow function. This is commonly done by defining a variable named self
or that
to capture this
inside a traditional function, and then passing self
or that
as an argument to an arrow function that needs to access this
.
By using a closure and passing this
as an argument, you can ensure that arrow functions have access to the correct this
value and avoid unexpected behavior. However, this approach can result in more verbose code, so it's generally only used when necessary.
Subscribe to my newsletter
Read articles from {{ MonaCodeLisa }} directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
{{ MonaCodeLisa }}
{{ MonaCodeLisa }}
Hello, I'm Esther White, I am an experienced FullStack Web Developer with a focus on Angular & NodeJS.