All topics
Functionsintermediate

Method Chaining and Fluent Interfaces

Designing functions/methods that return the calling object (usually this) so multiple calls can be strung together in one expression.

Chaining works because each method returns an object that has the next method on it.

Method chaining is like a factory assembly line where each station hands the same product straight to the next station without setting it down — you get to describe the whole process (weld, paint, inspect) in one continuous line instead of carrying the item back and forth between separate workbenches.

Key Concepts

1
    [1, 2, 3].filter(x => x > 1).map(x => x * 2);
2
filter returns an array, so map is available on it. Nothing special is happening.
filtermap
3
Building your own is the same trick: return this.
    class Query {
      constructor() { this.parts = []; }
      where(c)   { this.parts.push(`WHERE ${c}`); return this; }
      orderBy(f) { this.parts.push(`ORDER BY ${f}`); return this; }
      build()    { return this.parts.join(' '); }
    }
thisWHERE ${c}ORDER BY ${f}
4
    new Query().where('age > 18').orderBy('name').build();
5
The terminal method — build here — returns something else, which is what ends the chain.
build
6
The mutation question. The version above changes the object as it goes, so the builder is single-use and two references to it interfere.
7
    const base = new Query().where('active');
    const a = base.orderBy('name');
    const b = base.orderBy('date');    // a and b are the same object,
                                       // with both orderings
8
An immutable builder returns a new instance from each method:
9
    where(c) { return new Query([...this.parts, `WHERE ${c}`]); }
WHERE ${c}
10
More allocation, and base can now be reused safely. For a builder people share, that is worth it.
base
11
Where you meet fluent interfaces. jQuery, which popularised the style. Query builders such as Knex. Assertion libraries: expect(x).to.be.an('array').that.includes(2). And the array methods themselves.
12
When it hurts.Debugging. A single expression spanning six calls gives one line number. Breaking the chain into named intermediate values is the fastest way to find which step is wrong.
13
Errors. null partway through a chain fails with a message about the next method, not about the step that returned nothing.
null
14
Performance on arrays. Four chained array methods make four passes and three intermediate arrays. Fine at small sizes, worth collapsing into one reduce or loop when the array is large.
reduce
15
The design rule. Chain when each step is a transformation of the same kind of thing. When the steps are unrelated operations that happen to be on one object, a chain is just several statements without the newlines.
16
What the interviewer is probing.1. "What makes chaining work?" Probing: the mechanism. Stalls: "The methods are related." Moves up: each method returns this, or a new object of the same type, so the next call has something to act on.
17
2. "What is the downside of chaining?" Probing: the trade. Stalls: "None." Moves up: debugging is harder because there are no intermediate names, and a long chain hides where a value changed.
18
3. "How does an immutable fluent API differ?" Probing: the design choice. Stalls: "It is the same." Moves up: each method returns a new object rather than mutating and returning this, so an intermediate chain can be reused safely.
19
4. "Where does chaining appear in the standard library?" Probing: recognition. Stalls: "Nowhere." Moves up: array methods, promises and the DOM classList, all of which return something chainable.