How Arrow Functions redefine this in JavaScript
Learn how arrow functions simplify JavaScript by redefining this keyword
Why do popular frameworks and packages like Mongoose, Vue JS, and others say not to use arrow functions (in some places)? We’ll learn about this in this post but first what is even an 🏹 arrow function?
Arrow Functions; a concise and “elegant” way of writing functions in modern JavaScript. Converting regular function to an arrow function:
// Regular function
function getFood(food, quantity) {
return food.repeat(quantity);
}
// Arrow function
const getFood = (food, quantity) => {
return food.repeat(quantity);
};
// Directly returning
const getFood = (food, quantity) => food.repeat(quantity);
💡 For returning something directly using the arrow function, wrap it with parentheses ()
.
const breakfast = () => ({
food: "🥪",
quantity: 3,
});
This conciseness is what makes arrow functions so 💪🏽 powerful.
Difference between Arrow Functions and Regular Functions
Arrow functions are more than just syntactic sugar for writing functions. There are some nuances that make it different from a regular function like:
- It will implicitly return the value when you omit curly braces
{}
. For example:() => true
- It's always an expression and thus it can’t be hoisted
- 🔥 It doesn’t have its own
this
context as regular functions do.
The last point has some big implications. We will come back to this point but first, let’s look at the hoisting part.
Arrow Functions can’t be hoisted
Hoisting is the process where the interpreter moves the declaration of something to the top of their scope, prior to execution of the code. And because of this, you can something like this - run before wearing your 👟 shoes.
run();
function run() {
console.log("🐢 Running...");
}
// Output:
// 🐢 Running...
But this is not the case with function expressions, they can’t be hoisted. Other things that can’t be hoisted are variables declared using let
and const
and class expressions
. Since they are used before their definitions their value is set to undefined
.
console.log(run); // undefined
run(); // TypeError: run is not a function
var run = function () {
console.log("🐢 Running...");
};
// Output:
// undefined
// TypeError: run is not a function
Understanding this
context in Arrow Functions
this
context in arrow functions refers to its outer scope i.e. where was defined, unlike regular functions where this
context refers to the scope where it's being called.
class Food {
constructor() {
this.food = "🍞";
}
withArrowFunction() {
setTimeout(() => {
console.log(this.food);
}, 1000);
}
withRegularFunction() {
setTimeout(function () {
console.log(this.food);
}, 2000);
}
}
const food = new Food();
food.withArrowFunction(); // 🍞, since the function is defined in the Animal class
food.withRegularFunction(); // undefined, since the funciton is called in the global scope
So arrow functions remove this weird behavior of regular functions with respect to this
context. But there is more to this. When working with packages like Mongoose OR Vue JS there are some places where you’ve to use only regular functions and 🚫 not arrow functions.
So read the documentation for such things
A side history of problems of this
context in regular functions was handled prior to the dawn of arrow functions. The following example displays the limitations of this
context while using regular functions. A way around this limitation was to use a variable (mostly named self
) and assign its value to this
context thus you can use the self
variable consistently.
function getFood() {
let self = this;
this.food = "🍕 Pizza";
// Regular function in the callback
setTimeout(function () {
console.log(this.food); // undefined
console.log(self.food); // 🍕 Pizza
}, 1000);
// Arrow function in the callback
setTimeout(() => {
console.log(this.food); // 🍕 Pizza
}, 2000);
}
getFood();
// Output:
// undefined
// 🍕 Pizza
// 🍕 Pizza
Anatomy of the code snippet:
- 1️⃣ Inside the first
setTimeout
,this
refers to the scope where the callback is going to be called i.e. thesetTimeout
scope, where thefood
property isn’t defined, and because of this, we getundefined
. - 2️⃣ A hack was to use the concept of closures. A variable, usually named
self
, is defined in the scope to which you wantthis
context to refer. The value of this variable is thethis
context. Now JavaScript will close over the variableself
and you can use it consistently to refer tothis
context. - 3️⃣ Now, this is a dirty method and is removed by the use of the arrow function. In the arrow function,
this
context refers to the scope where the arrow function is defined.
Conclusion
Arrow functions are concise and do simplifies your code and make it easy to debug. Working with this
context is also simple. Hope this was helpful to you. If you liked this post then do 👍🏼 like and give your 🎙 feedback. ✅ Follow to stay up to date with my new posts.