arrow vs regular function

Differences

  1. Inside a regular function, the this value is dynamic. It depends on how the function is invoked.
    const person = {
    firstName: '',
    lastName: '',
    getFullName: function () {
    return `\${this.firstName} \${this.lastName}`;
    },
    };
    person.firtName = 'Foo';
    person.lastName = 'Bar';
    person.getFullName(); // 'Foo Bar'
    Arrow function does not have this. Accessing this inside an arrow function will refer to the this of its closest non-arrow parent function.
    const person = {
    yearOfBirth: new Date().getFullYear(),
    getAge: () => {
    return new Date().getFullYear() - this.yearOfBirth;
    },
    };
    person.yearOfBirth = 2000;
    person.getAge(); // NaN
    It is worth noting that calling arrowFunction.call(thisValue) or arrowFunction.apply(thisValue) do not change the this value.
  2. We can use the new keyword with a regular function to create new object.
    function Person(name, age) {
    this.name = name;
    this.age = age;
    }
    const foo = new Person('Foo', 42);
    On the other side, arrow functions do not own this value, hence they cannot be invoked with the new keyword.
    const person = (name, age) => {...}
    // ERROR: person is not a constructor
    const foo = new person('Foo', 42);
  3. Inside a regular function, we can use arguments which represents an array-like object of passed arguments. It is very useful if we want to access the parameters of a function whose number of parameters are dynamic.
    For example, the function below calculate the average of parameters:
    function average() {
    const args = [...arguments];
    return args.reduce((a, b) => a + b) / args.length;
    }
    average(1, 2); // 1.5
    average(1, 2, 3); // 2
    Arrow functions do not have arguments. Calling arguments inside an arrow function will return the arguments of closest non-arrow parent function.
    But it is still possible to get the list of dynamic passed parameters by using the rest parameters
    const average = (...args) => args.reduce((a, b) => a + b) / args.length;
    average(1, 2, 3, 4); // 2.5
    average(1, 2, 3, 4, 5); // 3
  4. We have to use the return statement in a regular function to return a result.
    function sum(a, b) {
    return a + b;
    }
    However, in an inline arrow function that contains only one expression, we can implicitly return the value by omitting the curly brackets. The sum function above can be rewritten as follow:
    const sum = (a, b) => a + b;
    Plus, arrow function also does not require parentheses if it has only one parameter:
    const sumOfArray = (arr) => arr.reduce((a, b) => a + b, 0);
  5. In non-restrict mode, regular functions allow us to use duplicate named parameters.
    The following declaration is accepted:
    function double(x, x) {
    return x + x;
    }
    double(3, 2); // 4
    double(3, 5); // 10
    This usage is not allowed in strict mode:
    'use strict';
    function double(x, x) { ... }
    // ERROR: Duplicate parameter name not allowed
    It is not possible to use the same name for different parameters in arrow functions, no matter the strict or non-strict mode is enabled.

Good practice

If the inline arrow function consists of the <, <=, > or >= operator, it is advised to wrap the function body in parentheses.
Looking at the two versions below, it is easy for the first variant to cause a misleading.
// Bad
const compareToZero = (a) => (a <= 0 ? 0 : a);
// Good
const compareToZero = (a) => (a <= 0 ? 0 : a);

Tip

You can use an underscore to name the argument which is not used in an arrow function. It makes the code more readable.
// No arguments
const noop = (_) => {};
const range = (min, max) =>
Array(max - min + 1)
.fill(0)
.map((_, i) => min + i);

Resource

You can find many useful arrow functions that have only single line of code at 1 LOC website.