JS - 03.03 - Arrow Function

Arrow functions are a concise syntax for defining functions using the => syntax, rather than the traditional function keyword. They offer several advantages, such as more concise syntax and different behavior for this.

let func = (arg1, arg2, ..., argN) => expression;

This defines a function func that takes parameters arg1, arg2, ..., argN, and evaluates the given expression.

  • Regular Function Expression:

    let func = function(arg1, arg2, ..., argN) {
      return expression;
    };
  • Arrow Function:

    let func = (arg1, arg2, ..., argN) => expression;

Examples of Arrow Functions

Basic Arrow Functions

  • Simple return (no block):
    let sum = (a, b) => a + b;   // Single expression, returns result automatically
    let double = n => n * 2;     // Single parameter, no need for parentheses around the parameter
    const square = x => x * x;   // Short form for single expression function
    let sayHi = () => alert("Hello");  // No parameters
    

When there is only one parameter, () can be omitted. If body is single expression, rather than a block in braces, that expression will be returned from the function even without return statement.

let age = prompt("What is your age?", 18);

let welcome = (age < 18) ? () => alert('Hello') : () => alert('Greetings');

Welcome();

// 18 is default, 
// if less than 18, hello
// otherwise greetings

Arrow Function with a Block (Multi-line)

If you need multiple statements in the function body, you must use curly braces {} and explicitly include the return statement.

const roundTo = (n, step) => {
  let remainder = n % step;
  return n - remainder;
};

let sum = (a, b) => {
  let result = a + b;
  return result;
};

alert(sum(1, 2));  // 3

Arrow Function with No Parameters

When there are no parameters, use empty parentheses ():

const horn = () => {
  console.log("Toot");
};

Arrow Function as Arguments

Arrow functions can be used in the same way as regular functions, including as arguments to other functions.

function ask(question, yes, no) {
  if (confirm(question)) yes();
  else no();
}

ask(
  "Do you agree?",
  () => alert("You agreed."),
  () => alert("You canceled the execution.")
);
ask(
	"Do you agree?",
	function() { alert("You agreed.");},
	function() { alert("You canceled the execution."); }
);

Arrow Functions and this

Arrow functions behave differently from regular functions when it comes to the this keyword. They do not have their own this. Instead, they inherit this from the lexical scope (i.e., the surrounding context).

Arrow Functions Inheriting this

let user = {
  firstName: "John",
  sayHi() {
    let arrow = () => alert(this.firstName);  // `this` refers to the `user` object
    arrow();
  }
};

user.sayHi();  // Output: "John"

In this example, the arrow() function inherits this from the sayHi() method, which refers to the user object.

Arrow Functions in forEach and Similar Methods

Arrow functions are useful in methods like forEach because they preserve the this context from the surrounding code:

let group = {
  title: "Our Group",
  students: ["John", "Pete", "Alice"],
  showList() {
    this.students.forEach(
      student => alert(this.title + ': ' + student)  // `this` refers to `group`
    );
  }
};

group.showList();  // Output: "Our Group: John", "Our Group: Pete", "Our Group: Alice"

In this case, the arrow function inside forEach inherits this from the showList() method, which refers to the group object.

Regular Function in forEach

If we use a regular function inside forEach, the value of this changes to undefined in strict mode, or the global object (window in browsers) in non-strict mode:

let group = {
  title: "Our Group",
  students: ["John", "Pete", "Alice"],
  showList() {
    this.students.forEach(function(student) {
      alert(this.title + ': ' + student);  // Error: `this` is undefined or refers to the global object
    });
  }
};

group.showList();  // Error: Cannot read property 'title' of undefined

Error because when forEach runs function with this=undefined by default. This doesn’t affect arrow functions because they don’t have this.

Here, the function passed to forEach does not have its own this and refers to the global context instead of the group object, leading to an error.

  • Regular functions create their own this context, which means inside the forEach method, this is no longer the group object.
  • Arrow functions do not create their own this; instead, they inherit it from the surrounding scope, making them ideal for cases like the forEach method where you want to preserve the context.

Arrow Functions Cannot Be Used as Constructors

Since arrow functions do not have their own this, they cannot be used as constructors. You cannot call an arrow function with new.

const Person = (name) => {
  this.name = name;
};

let john = new Person("John");  // Error: Person is not a constructor

In this example, Person is an arrow function, and calling it with new will throw an error because arrow functions don’t have their own this, which is required for object creation via new.


Summary of Arrow Functions

  • Syntax: Arrow functions use the => syntax, making them more concise than regular function expressions.
  • No this binding: Arrow functions do not have their own this. Instead, they inherit it from the surrounding scope, making them useful for methods like forEach.
  • Single-expression functions: If the body is a single expression, the return keyword is implicit, and you can omit the curly braces.
  • Cannot be used as constructors: Arrow functions cannot be invoked with new because they do not have their own this.

Arrow Function Quick Reference

FeatureArrow FunctionRegular Function
Syntax() => expressionfunction() { return expression; }
this BindingInherited from the outer scope (lexical this)this is dynamic, based on the call site
ConstructorCannot be used as a constructor (new is not allowed)Can be used as a constructor
Implicit returnYes, for single expressionsNo, needs an explicit return statement
Parameter ParenthesesOmit parentheses for a single parameterAlways require parentheses