You can hear the question about regular functions versus arrow functions in almost every interview. There are several differences, and now we will go through them in detail:
Syntactic sugar
The most obvious, but not the most important, difference is the convenience and conciseness of arrow functions. Below, I will give a few examples of how you can simplify small functions.
Arguments
An arrow function does not have its own array-like arguments object. This is because arrow functions follow the Lambda philosophy and are designed to be lightweight and as simple as possible. Besides that, arguments is considered a legacy API, and today you can use a more modern approach - Rest parameters.
Hoisting
A regular function declared with the function keyword is hoisted to the top. This means that even if you write the function at the very bottom, you can still call it anywhere.
An arrow function is created as a variable value and is not hoisted. So you can only call it after it has been defined. If you call it before the declaration, you will get an error.
New
Regular functions can be called as a constructor with new, whereas with an arrow function this will not work and will throw an error. This is because an arrow function does not have the internal [[Construct]] property, so it cannot be a constructor.
Execution context (this)
The last and most important difference is that an arrow function has no execution context of its own. This is done for the same reason as the absence of arguments, and it makes the function as simple as possible, in line with the Lambda philosophy.
In a regular function declared with the function keyword, this depends on where it is called (call-site). Whereas in an arrow function, this is taken from the outside - from where it was declared (the lexical scope). This makes an arrow function safer in terms of the predictability of the execution context.