liveBook · Manning

Composition

As explained in The Joy of JavaScript

A pipeline is a composition pattern where output from one stage becomes input to the next stage in sequence.

Function composition builds a function by connecting smaller functions: one function’s result becomes the next function’s input. It lets each step have a narrow job while the assembled function expresses a larger process. For `f(g(value))`, `g` runs first, so `compose(f, g)` reads from right to left. section 4.3

Count words in a string

Define `split = str => str.split(/\s+/)` and `count = arr => arr.length`. Then `const countWords = compose2(count, split)` creates a reusable function: `countWords('functional programming')` returns `2`. A two-function combinator can be written as `const compose2 = (f, g) => (...args) => f(g(...args))`. section 4.3

Start by identifying steps, then give each one a function. Counting words in a file separates reading, decoding, splitting, and counting. The resulting chain, `compose(count, split, decode, read)`, shows the process without intermediate assignments. Reading the file still has a side effect; keep that step apart from the pure transformations rather than treating the whole chain as pure. section 4.3.1

A chain works best when its steps fit together:

  • Prefer predictable, side-effect-free transformations for the core logic; they are easier to rearrange and reason about. section 4.1 section 4.3.1
  • Match each stage’s input to the preceding stage’s output. If a function also needs configuration, curry or partially apply it first; `decode('utf8')` leaves a function ready to receive a buffer. section 4.4.1 section 4.4.2
  • Choose the presentation that makes the flow clearest: `compose` lists stages right to left, while `pipe` lists them left to right. Curried array operations can also turn a method chain into a composed, point-free function. section 4.8 section 4.7

Composition is not limited to strings. A balance calculation can filter blocks, collect transactions, map them to amounts, reduce them, and round the result. A hashing operation can compose property selection, assembly, and a configured hash function. These examples show how a larger operation can be assembled from replaceable parts. section 4.7 section 4.4.2

A direct function chain assumes usable inputs and well-defined outputs. Validation and exception handling complicate that flow; algebraic data types offer a way to compose operations while representing failure. The same output-to-input idea also appears in promise chains and observable operators, where values move through asynchronous or streamed stages. section 5.0 section 8.2.2 section 9.4.3

How The Joy of JavaScript covers it

How deep it goes
Defines execution order, implements compose2 and compose, and works through refactoring, currying, side effects, and point-free chains.
Examples
Uses string and file word counts, transaction hashing, and blockchain balance calculations as composed workflows.
What it assumes
Assumes familiarity with JavaScript functions and array operations; teaches the composition combinator and introduces currying where stage signatures need adjustment.
What you can do after
Build it from scratch with compose2 and compose, then apply it to assemble reusable functions and separate pure transformations from file reading.
How it connects
Connects pure functions, higher-order functions, currying, point-free programming, algebraic data types, promises, and observables.

Also explained in

Compare how 11 books explain composition →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of The Joy of JavaScript. The section links point to the parts of the book it draws on.