Side effect in JavaScript: everything a function does beyond returning a value

A side effect is any action of a function observable from outside it: writing, printing, calling a service or modifying one of its arguments.
3 min read
Believemy logo

A function meant to compute a total also writes a line to a log, updates a global counter and sends a metric to an analytics service. Its name says none of that.

Those extra actions have a name: side effects. They are neither forbidden nor suspicious, but they change how a function is tested and read.


Definition

A side effect is any action of a function observable from the outside, beyond the value it returns. Modifying a shared variable, writing to browser storage, printing something, calling a service: all of it counts.

JAVASCRIPT
let log = [];

function pureSum(numbers) {
  return numbers.reduce((total, n) => total + n, 0);
}

function sumWithEffect(numbers) {
  log.push("summed " + numbers.length + " values"); // side effect
  return pureSum(numbers);
}

console.log(sumWithEffect([1, 2, 3])); // 6
console.log(log);                      // [ 'summed 3 values' ]

Both functions return the same value. The second one also leaves a trace in the program, and that trace is invisible to anyone reading only its call.


The most common forms

  • Modifying a received argument: a Mutation the caller never asked for. The most insidious of the four.
  • Writing an outside variable: a global counter, a cache, a state flag.
  • Touching the outside world: localStorage, a fetch() call, a line printed to the console.
  • Throwing an error: a throw diverts the program flow, which is an effect too.


The problem is not the effect, it is its scattering

A program with no effects is useless: it shows nothing and records nothing. What costs is an effect hidden in the middle of a function that looks like it only computes.

The practice is to gather the effects in one place, usually the edge of the application, and keep the rest as Pure function. Concretely, one function computes and returns, another takes that result and writes it somewhere.

Good to know

A simple signal for spotting them: if the function name starts with a computing verb but its body contains a write, there are two responsibilities inside one function.


Frequently asked questions

Question

Is a console.log() really a side effect?

Technically yes, since it writes outside the function. In practice it is harmless: it changes no data and disappears without consequence. The question is only worth asking when console output becomes a logging mechanism other systems rely on.


Question

How do I test a function that produces one?

By replacing the dependency with a controlled double, a mock, and checking that it was indeed called. It is doable but always longer than testing a pure function. The best saving is often to extract the computation into a separate function, tested directly.


Question

Does Array.forEach() necessarily produce an effect?

Almost always, yes, since it returns nothing: its only point is to do something on each pass. When you want to produce a value rather than act, Array.map() or Array.reduce() express the intent better and leave the original data alone.

Related terms

Discover our javaScript glossary

Every word of JavaScript explained simply: keywords, built-in objects, methods, errors and concepts. Clear definitions and examples that actually run, to learn and to troubleshoot.

Share this article

Want to help us? Share this article on your networks or even better: on your site, in an article or in your newsletter.