We learned about arrow functions and the this
keyword in previous blog posts. Now we will combine the two and see how arrow functions behave differently compared to standard function expressions.
Arrow functions, for the most part, work like function expressions with a concise syntax. The critical difference is that arrow functions do not have their bindings to this
keyword.
For a function expression, this
changes based on the context a function is called in. For arrow functions, this
is based on the enclosing lexical scope. Arrow functions follow normal variable lookup. They look for this
in the current scope, and if not found, they move to the enclosing scope.
We will use the same scenarios as the previous blog post.
- By itself.
- When used in a constructor.
- Called as a method of the object.
- In the case of strict mode.
- In an event.
Let us use arrow functions in the above five examples and see how they behave:
By itself
const foo = () => {
return this;
}
console.log(foo()); // window or global object
Exactly same as function expressions.
When used in a constructor.
const Order = (main, side, dessert) => {
this.main = main;
this.side = side;
this.dessert = dessert;
this.order = function () {
return `I will have ${this.main} with ${this.side} and finish off with a ${this.dessert}`;
}
}
const newOrder = new Order("sushi", "soup", "yogurt"); // Order is not a constructor
console.log(newOrder.order());
Arrow functions cannot be used as constructors. They differ in this case. Although changing the this.order
to an arrow function would work the same if we did not use the arrow function as a constructor.
function Order(main, side, dessert) {
this.main = main;
this.side = side;
this.dessert = dessert;
this.order = () => {
return `I will have ${ this.main } with ${ this.side } and finish off with a ${ this.dessert } `;
}
}
const newOrder = new Order("sushi", "soup", "yogurt");
console.log(newOrder.order());
// I will have sushi with soup and finish off with a yogurt
Called as a method of the object.
const myObject = {
main: "butter chicken",
side: "rice",
dessert: "ice cream",
order: () => {
return `I will have ${this.main} with ${this.side} and finish off with ${this.dessert}`;
}
}
console.log(myObject.order());
// I will have undefined with undefined and finish off with undefined
Does not work at all like function expressions!. Arrow functions are not direct replacements of function expressions when used as methods of an object.
Why did it provide undefined
for the variables main, side, and dessert? The this
within the arrow function is the one that was current where we defined the object myObject
(in this example window). The window does not have the three variables order
is looking for.
In the case of strict mode.
"use strict";
const foo = () => {
return this;
};
console.log(foo() === undefined); // false
console.log(foo()); // window or global object
Does not work at all like function expressions! because the rules of lexical this
take precedence over strict-mode this
rules.
In an event.
<!DOCTYPE html>
<html lang="en">
<head>
<meta content="text/html;charset=utf-8" http-equiv="Content-Type">
<meta content="utf-8" http-equiv="encoding">
</head>
<body>
<button id="mybutton">
Click me!
</button>
<script>
var element = document.querySelector("#mybutton");
element.addEventListener('click', (event) => {
console.log(this); // window object
console.log(this.id); // undefined
}, false);
</script>
</body>
</html>
Does not work at all like function expressions! The value of this
inside an arrow function is determined by where the arrow function is defined, not where it is used. In this example, we can access the element using event.currentTarget.
We can read more here.
Summary: Except when using it on its own, arrow function behaves differently compared to function expressions. They are concise and provide advantages but do know when not to use them as a direct replacement of function expressions.
Top comments (0)