An Introduction to JavaScript Arrow Functions

An Introduction to JavaScript Arrow Functions

What are Arrow Functions?

Arrow functions were introduced with ES6 as an alternative way to write functions in JavaScript. The newer syntax made it possible to execute the same logic with a shorter syntax, resulting in the code being more readable.

ES6 (aka: ECMAScript 6 or ECMAScript 2015) is the “6th version” of JavaScript, released in 2015. Some notable features include the addition of Constants, Block-Scoped Variables and Functions, Arrow Functions, and Default Function Parameters, amongst others.

Arrow Function Syntax

The syntax of an arrow function is:

let myFunc = (arg1, arg2, ...argN) => expression

Here:

  • myFunc is the name of the function

  • arg1, arg2, ...argN are the function arguments

  • expression is the function body

If the body has multiple statements or expressions, it can be written using the following syntax:

let myFunc = (arg1, arg2, ...argN) => {
     statement(s)
}

Arrow functions can be written in different ways based on the number of parameters it accepts and the kind of operation it performs.

// function without arguments
const hello = () => console.log("Hello");

// function with one argument
const input = num => console.log(num);

// function with multiple arguments
const sum = (x, y) => x + y;

// multiple statements in function 
const product = (x, y) => {
    console.log(`Multiplying ${x} and ${y}`);
    return x + y;
}

Arrow Functions Use cases

With Array Methods

Clean and concise code can be written using array methods like .map(), .sort(), filter() etc when arrow functions are used to pass the callback functions.

const numbers = [4, 2, 5, 1, 3];
const sorted = numbers.sort((a, b) => a - b));

This becomes more apparent if more than one array method is to be applied to an array since methods cab be chained together.

let numbers= [1,2,3].map(num => num + 1).filter(num => num > 3);

Arrow functions were introduced in ES6. Some browsers may not support the use of arrow functions

Promise Chaining

The promise chaining sometimes end up looking confusing with repetitive function and return keywords.Arrow functions provide better syntax to write promises

asyncFunc1()
.then(() => asyncFunc2())
.then(() => asyncFunc3())
.then(() => finish);

Differences from Normal Functions

Arrow functions have no “this”

Inside a regular function, this keyword refers to the function where it is called. On the other hand, If this is accessed in an arrow function, it is taken from the outside. For example, here name() uses this from the outer user.printFirstName() method:

const user = {
  fName: "Daniel",
  printFirstName() {
    let name = () => console.log(this.fName);
    name();
  }
};

user.printFirstName(); // Daniel

The value of this inside an arrow function remains the same throughout the lifecycle of the function and is always bound to the value of this in the closest non-arrow parent function.

This restricts the use of arrow functions as object methods. See the following counter object:

const counter = {
  count: 0,
  next: () => ++this.count,
};

The counter object has one method: next(). The next() method returns the next counter value.

The following shows the next counter value which should be 1:

console.log(counter.next());

However, it returns NaN.

The reason is that when you use the arrow function inside the object, it inherits the this value from the enclosing lexical scope which is the global scope in this example.
The this.count inside the next() method is equivalent to window.count (in the web browser).
The window.count is undefined by default because the window object doesn’t have the count property. The next() method adds one to undefined that results in NaN.

Arrow functions are not hoisted

Because of this, you cannot call them before they are declared

//normal function
printUserNameNF("Daniel");  // outputs Daniel
printUserNameNF(name){
    console.log(name);
}

//arrow function
printUserNameAF("Daniel");  // throw Reference Error
printUserNameAF = (name) => console.log(name);

Arrow functions and the arguments object

The arguments object is a local variable available within all non-arrow functions. It allows us to refer to a function's arguments inside that function by using its arguments object. However, an arrow function doesn’t have thearguments object.

function count() {
    console.log(arguments.length); 
}
count('a', 'b', 'c', 'd') // outputs 4

const count = () => {
    console.log(arguments.length); 
}
count('a', 'b', 'c', 'd') // throws Reference Error: arguments not found

Quick Cheatsheet

  1. Must use empty parentheses if a function doesn't take any arguments.

  2. Optional parentheses in case of single argument.

  3. Must use parentheses in case of multiple arguments.

  4. return keyword and curly brackets required in case of multiple statements in a function.

  5. Rest operator, default parameters, and parameter destructuring work normally.

Conclusion

Arrow functions are really awesome and have short, clean and concise syntax which makes it very easy for developers to write clean code. They are meant for short pieces of code that do not have their own “context”, but rather work in the current one. And they really shine in that use case.