---
title: 'Arrow Functions'
source: 'https://academia.sh/en/courses/javascript-fundamentals/arrow-functions'
course: 'JavaScript Fundamentals'
language: en
updated: '2026-08-17T18:09:46+00:00'
license: 'CC BY-SA 4.0'
---

# Arrow Functions

The forms of the short syntax, the implicit return and object-return trap, the absence of the arguments object, and context coming from the enclosing scope.

Earlier lessons used spellings like `(d) => d > threshold` unexplained. This lesson
defines that syntax. The arrow function is a third function-definition form and offers
two gains: brevity and a change in context behavior.

The second is the real one. Brevity sometimes improves readability and sometimes
reduces it; context behavior, on the other hand, is what makes an arrow function
unusable in some places. By the end of this lesson, which form to choose where will be
tied to a rule.

## Syntax Forms

An arrow function consists of a parameter list and a body, separated by `=>`.

```js
const square = (x) => x * x;
const singleParam = x => x * 2;
const two = (a, b) => a + b;
const zero = () => 42;
const withBody = (array) => {
  let total = 0;
  for (const value of array) total += value;
  return total;
};

console.log(square(4), singleParam(4), two(1, 2), zero());
console.log(withBody([21.5, 19.75]));
```

```
16 8 3 42
41.25
```

Parentheses can be omitted for a single parameter; they are required for the
no-parameter and multi-parameter forms. In this course, parentheses will always be
written — a single form reduces the change needed when a parameter is added.

The body comes in two kinds. A body without curly braces is an **expression**, and its
value is implicitly returned; `return` is not written. A body with curly braces is a
**block**, and the return is written explicitly. Without `return`, the `withBody`
function's result would have been `undefined`.

## The Object-Return Trap

Returning an object with an implicit return creates a syntactic ambiguity: does the
opening curly brace mean an object, or a block?

```js
const broken = (name) => { station: name };
console.log(broken("A1"));
```

```
undefined
```

The parser read the curly braces as a block. The line `station: name` inside the block
is not an object property, it is a statement labeled `station` — the same labeled-loop
syntax as the Loops lesson. Because the block has no `return`, the result was
`undefined`. No error was thrown.

The fix is to wrap the object in parentheses:

```js
const returnsObject = (name) => ({ station: name });
console.log(returnsObject("A1"));
```

```
{ station: 'A1' }
```

The parentheses signal that the curly braces are in an expression context; the parser
now reads an object.

## No Arguments Object

Arrow functions have no `arguments` object of their own:

```js
const arrowFn = () => {
  try {
    return arguments.length;
  } catch (error) {
    return error.name + ": " + error.message;
  }
};
console.log(arrowFn(1, 2));
```

```
ReferenceError: arguments is not defined
```

The message says "not defined" — an arrow function does not define such a name. A
variable number of arguments is taken with a rest parameter:

```js
const withRest = (...args) => args.length;
console.log(withRest(1, 2));
```

```
2
```

The rule set in the Parameters lesson becomes mandatory here.

## Context Comes From the Enclosing Scope

Arrow functions have no `this` binding of their own. The `this` in the body is the
`this` value **where the function is defined**. The lexical scope principle
established in the Naming and Scope Rules lesson also applies to binding in arrow
functions.

The rules of `this` binding are the next course's subject. Here, only the observed
difference is covered, and it shows up most in callback functions:

```js
const watcher = {
  threshold: 20,
  temperatures: [21.5, 19.75, 23],

  classicCallback() {
    try {
      return this.temperatures.filter(function (d) {
        return d > this.threshold;
      });
    } catch (error) {
      return error.name + ": " + error.message;
    }
  },

  arrowCallback() {
    return this.temperatures.filter((d) => d > this.threshold);
  },
};

console.log(watcher.classicCallback());
console.log(watcher.arrowCallback());
```

```
TypeError: Cannot read properties of undefined (reading 'threshold')
[ 21.5, 23 ]
```

Both methods were called on the same object, and the outer `this` was the object
itself in both. The difference is in the inner function. The classic function
expression establishes its own `this` binding; in strict mode this binding is
`undefined`, and reading a property throws an error. The arrow function establishes no
binding of its own, uses the outer one, and the filter works as expected.

The same behavior also produces a result in the opposite direction. When an arrow
function is written as an object method, `this` does not bind to the object:

```js
const station = {
  name: "A1",
  classicMethod() {
    return this === undefined ? "this: undefined" : `this.name: ${this.name}`;
  },
  arrowMethod: () => {
    return this === undefined ? "this: undefined" : `this.name: ${this.name}`;
  },
};
console.log(station.classicMethod());
console.log(station.arrowMethod());
```

```
this.name: A1
this: undefined
```

The arrow function took the `this` value of where it was defined. Because this example
runs in a module file, the outermost `this` value is `undefined` — the module rule
shown in the Ways to Run Code lesson. The same line in script mode would give a
different value; in neither case would it be the object itself.

The rule follows from this: **object methods are not written as arrow functions.**

## Cannot Be Used as a Constructor

Arrow functions cannot be called with `new`:

```js
const Measurement = (name) => { this.name = name; };
try {
  new Measurement("A1");
} catch (error) {
  console.log(error.name + ": " + error.message);
}

function ClassicMeasurement(name) { this.name = name; }
console.log(new ClassicMeasurement("A1").name);
console.log(typeof Measurement.prototype, typeof ClassicMeasurement.prototype);
```

```
TypeError: Measurement is not a constructor
A1
undefined object
```

The last line shows the reason: an arrow function has no `prototype` property. Why a
constructor call needs this property, and how the prototype chain is built, is the
next course's subject.

## Choosing a Form

The choice among the three definition forms comes down to these rules:

- **Declaration:** named helper functions in the outermost scope. Because it is
  hoisted, the file's order is free.
- **Arrow function:** short callbacks passed to another function, and inner functions
  that need to use the enclosing context.
- **Classic function expression:** object methods and cases where `this` binding
  should be determined by the call site.

An arrow function is not short everywhere. An operation whose body runs past a few
lines and carries meaning on its own becomes both more readable and reusable when
pulled out into a named declaration.

## Applying It to the Measurement Script

Transformation chains are arrow functions' best-fitting use:

```js
const records = [
  { station: "A1", temperature: 21.5 },
  { station: "A2", temperature: NaN },
  { station: "B1", temperature: 23 },
  { station: "B2", temperature: 18.25 },
];

const THRESHOLD = 20;

const valid = (record) => !Number.isNaN(record.temperature);
const aboveThreshold = (record) => record.temperature > THRESHOLD;
const label = (record) => `${record.station}=${record.temperature}`;

console.log(records.filter(valid).filter(aboveThreshold).map(label));

console.log(
  records
    .filter((r) => !Number.isNaN(r.temperature))
    .map((r) => ({ ...r, deviation: r.temperature - THRESHOLD })),
);
```

```
[ 'A1=21.5', 'B1=23' ]
[
  { station: 'A1', temperature: 21.5, deviation: 1.5 },
  { station: 'B1', temperature: 23, deviation: 3 },
  { station: 'B2', temperature: 18.25, deviation: -1.75 }
]
```

Both spellings belong to the same family. In the first, the filters were named and the
chain stayed readable; in the second, short callbacks were written in place. In the
second output, an object was returned, so the parentheses were required — the trap
from this lesson's second section.

The multi-line display in the second output is the runtime's inspection format; an
array is broken into lines once it exceeds a certain length. This format is not
defined in the standard and varies across environments.

The object spread syntax (`{ ...r }`) was used here and will be defined in the Objects
lesson.

## Summary

- In an arrow function, parentheses can be omitted for a single parameter; a body
  without curly braces is an expression and its value is implicitly returned.
- To return an object with an implicit return, the object is wrapped in parentheses;
  without it, the curly braces are parsed as a block and the result is `undefined`.
- Arrow functions have no `arguments` object; a variable number of arguments is taken
  with a rest parameter.
- An arrow function's `this` value comes from the scope it is defined in; this is the
  desired behavior in callbacks and the undesired behavior in object methods.
- Arrow functions cannot be called with `new`; they have no `prototype` property.

## Next Step

In this topic's examples, error conditions were caught with `try`/`catch`, but the
structure was never defined. The next lesson covers error handling: the flow of
`try`/`catch`/`finally` blocks, the `throw` statement, built-in error types, and
defining your own error type. The measurement script's response to broken data will
also be tied to a contract there.
