What you'll be able to do

By the end of this page you should be able to rewrite a small function expression as an arrow function, use the one-expression return shortcut safely, and choose arrows for short callbacks without forcing them everywhere. We will not go deep on this yet — that comes later when it pays off.

Previous post: function declarations vs expressions.

Who this is for

  • People who see (n) => n * 2 in examples and want the plain-English version
  • Beginners who copy arrows into every helper and make longer code harder to read
  • Anyone unsure when {} need an explicit return

You can skip this if you already write arrows for short maps/callbacks and keep function for named multi-step helpers. Come back when a missing return in an arrow body returns undefined.

The same idea, shorter spelling

An arrow function is another way to write a function expression (a value), not a declaration.

const double = function (n) {
  return n * 2;
};

const doubleArrow = (n) => {
  return n * 2;
};

console.log(double(5));
console.log(doubleArrow(5));

Both log 10.

Scenario A — assign to const. Same call rules as the last post: define the const before you call it.

Scenario B — pass inline. You will often see arrows as the second argument to something later (map, timers). For now, named const arrows are enough to learn the shape.

If there is exactly one parameter, parentheses are optional: n => n * 2. Zero parameters need (): () => console.log("hi"). Two or more need parentheses: (a, b) => a + b.

One-line return (implicit return)

If the body is a single expression, you can drop the braces and return:

const double = (n) => n * 2;
console.log(double(5));

Scenario A — tiny transform. Double, trim, add tax — one expression, arrow fits.

Scenario B — you need two statements. Then use braces and return:

const label = (n) => {
  const safe = Number(n);
  return "Value: " + safe;
};

If you write (n) => { n * 2 } without return, the function returns undefined. The braces start a block, not an expression. That is a common arrow trap.

Returning an object from a one-liner needs parentheses so {} are not read as a block: () => ({ ok: true }).

When arrows help

Scenario A — short callbacks you will meet soon. “For each item, do this small thing.” Arrows keep the focus on the work, not the function keyword.

Scenario B — keeping a helper next to related const values. A cluster of small pure helpers as arrows can read like a toolkit.

When a normal function is clearer

Scenario A — a named multi-step procedure. Validation, several early returns, comments — a function processForm() {} declaration or a longer expression is often easier to scan than a fat arrow.

Scenario B — you do not know this yet. Arrow functions treat this differently from function. Until we cover this on purpose, prefer normal function for DOM methods and object methods you copy from old tutorials. Using arrows “by habit” on methods is a classic future bug.

Rule of thumb for this series: arrows for short data transforms; function for named, multi-step work and anything method-like until this is taught.

A tiny practice file

Save as arrows.html. Compare expression vs arrow vs one-liner.

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>Arrows</title>
  </head>
  <body>
    <button id="go">Run</button>
    <pre id="out">Result will show here.</pre>
    <script>
      const doubleExpr = function (n) {
        return n * 2;
      };
      const doubleArrow = (n) => {
        return n * 2;
      };
      const doubleShort = (n) => n * 2;

      document.getElementById("go").addEventListener("click", function () {
        const lines = [];
        lines.push("expression: " + doubleExpr(4));
        lines.push("arrow block: " + doubleArrow(4));
        lines.push("arrow short: " + doubleShort(4));
        document.getElementById("out").textContent = lines.join("\n");
      });
    </script>
  </body>
</html>

All three should show 8. Then try (n) => { n * 2 } without return in the console — you will get undefined.

Mistakes I see a lot

1. Block body without return. (n) => { n * 2 } returns undefined.

2. Arrow “declarations” at the top of a file, called above the const. Same TDZ rules as other const expressions.

3. Using arrows for every object method by default. Wait until you understand this.

4. Forcing a long helper into a one-liner. Readability beats cleverness.

5. Confusing => with a comparison. >= is greater-or-equal; => is an arrow function.

What to try before the next post

  1. Rewrite const add = function (a, b) { return a + b; } as an arrow.
  2. Write the short form (a, b) => a + b.
  3. Break a one-liner by wrapping {} without return; fix it.
  4. Build the tiny HTML file.

Next in this series: scope and hoisting plainly — where names live, the temporal dead zone, and why a variable looks undefined or throws before its line.

Try this next outside the series

Functions matter more once they stop being textbook examples and start shaping reusable app code.

  • Node.js async patterns — see functions return promises, accept callbacks, and coordinate real work
  • Diff Checker — compare two function versions before you keep a refactor