Where Arrow Functions Improve Your Code ( where you should use them ) -
One of the primary use cases for traditional lambda functions, and now for arrow functions in JavaScript, is for functions that get applied over and over again to items in a list.
For example, if you have an array of values that you want to transform using a map, an arrow function is ideal:
const words = ['hello', 'WORLD', 'Whatever'];
const downcasedWords = words.map(word => word.toLowerCase());
An extremely common example of this is to pull out a particular value of an object:
const names = objects.map(object => object.name);
Similarly, when replacing old-style for loops with modern iterator-style loops using forEach, the fact that arrow functions keep this from the parent makes them extremely intuitive.
this.examples.forEach(example => {
this.runExample(example);
});
Promises and Promise Chains - Another place arrow functions make for cleaner and more intuitive code is in managing asynchronous code.
Promises make it far easier to manage async code (and even if you're excited to use async/await, you should still understand promises which is what async/await is built on top of!)
However, while using promises still requires defining functions that run after your asynchronous code or call completes.
This is an ideal location for an arrow function, especially if your resulting function is stateful, referencing something in your object. Example:
this.doSomethingAsync().then((result) => {
this.storeResult(result);
});
Object Transformations -
Another common and extremely powerful use for arrow functions is to encapsulate object transformations.
For example, in Vue.js there is a common pattern for including pieces of a Vuex store directly into a Vue component using mapState.
This involves defining a set of "mappers" that will transform from the original complete state object to pull out exactly what is necessary for the component in question.
These sorts of simple transformations are an ideal and beautiful place to utilize arrow functions. Example:
export default {
computed: {
...mapState({
results: state => state.results,
users: state => state.users,
});
}
}
Where You Should Not Use Arrow Functions -
There are a number of situations in which arrow functions are not a good idea. Places where they will not only help, but cause you trouble.
The first is in methods on an object. This is an example where function context and this are exactly what you want.
There was a trend for a little while to use a combination of the Class Properties syntax and arrow functions as a way to create "auto-binding" methods, e.g. methods that could be used by event handlers but that stayed bound to the class.
This looked something like:
class Counter {
counter = 0;
handleClick = () => {
this.counter++;
}
}
In this way, even if handleClick were called with by an event handler rather than in the context of an instance of Counter, it would still have access to the instance's data.
The downsides of this approach are multiple,
While using this approach does give you an ergonomic-looking shortcut to having a bound function, that function behaves in a number of ways that are not intuitive, inhibiting testing and creating problems if you attempt to subclass/use this object as a prototype.
Instead, use a regular function and if necessary bind it the instance in the constructor:
class Counter {
counter = 0;
handleClick() {
this.counter++;
}
constructor() {
this.handleClick = this.handleClick.bind(this);
}
}
Deep Callchains -
Another place where arrow functions can get you in trouble is when they are going to be used in many different combinations, particularly in deep chains of function calls.
The core reason is the same as with anonymous functions - they give really bad stacktraces.
This isn't too bad if your function only goes one level down, say inside of an iterator, but if you're defining all of your functions as arrow functions and calling back and forth between them, you'll be pretty stuck when you hit a bug and just get error messages like:
{anonymous}()
{anonymous}()
{anonymous}()
{anonymous}()
{anonymous}()
Functions With Dynamic Context -
The last situation where arrow functions can get you in trouble is in places where this is bound dynamically.
If you use arrow functions in these locations, that dynamic binding will not work, and you (or someone else working with your code later) may get very confused as to why things aren't working as expected.
Some key examples of this:
- Event handlers are called with this set to the event's currentTarget attribute.
- If you're still using jQuery, most jQuery methods set this to the dom element that has been selected.
- If you're using Vue.js, methods and computed functions typically set this to be the Vue component.
Certainly you can use arrow functions deliberately to override this behavior, but especially in the cases of jQuery and Vue this will often interfere with normal functioning and leave you baffled why code that looks the same as other code nearby is not working.
this excerpt is taken from here