Arrow Functions

Objective

There are two main ways to write functions in JavaScript:

  1. function foo() { … } (regular function declarations/expressions)
  2. const foo = () => { … } (arrow functions)

We want to pick one default style for our codebase and enforce it.

Our codebase:

  • Does not use classes or object-oriented patterns
  • Follows a functional programming style (pure functions, no this, no new, no prototypes)

Decision

Default Rule

If you write a function in our codebase, write it as an arrow function.

Examples

Allowed:

const sum = (a, b) => a + b;
const doubleAll = (xs) => xs.map(x => x * 2);

Not allowed (without a specific reason):

function sum(a, b) {
  return a + b;
}

[1, 2, 3].map(function (x) {
  return x * 2;
});

We also use rest parameters instead of arguments:

const logAll = (...args) => {
  console.log(args);
};

Note: Regular functions allowed for library/framework requirements, constructors, or generators where arrow functions aren't supported.

Rationale

We don't use classes, this, or OOP patterns, so most traditional differences between regular and arrow functions don't matter for us. What's left are readability, consistency, and a few minor language features:

Aspect Regular Functions Arrow Functions Our Take
this / OOP Own dynamic this, used in classes/objects Lexically inherits this We avoid this and OOP; not needed
arguments Has arguments (array-like) No own arguments We prefer ...args everywhere
Constructors / new Can be used with new, has prototype Cannot be used with new We don't design with constructors
Hoisting Declarations are hoisted Expressions are not hoisted We are fine defining before use
Readability / style More verbose, mixed styles possible Short, uniform, matches FP style Clearer, more concise
Performance (our usage) Optimized by engines Optimized by engines No meaningful difference

Consequences

Positive

  • Single, simple rule: "Use arrow functions by default"
  • More concise and readable functional-style code
  • Consistent codebase; easier for new devs to follow
  • Naturally discourages OOP patterns we don't want (constructors, this-heavy code)

Negative / Trade-offs

  • No hoisting: functions must be defined before they're used
  • Need exceptions (escape hatch) when dealing with certain libraries/frameworks
  • Developers must know when a regular function is justified and comment accordingly