The same group of fields (low, high; firstName, lastName; street, city, zip) appears as parameters across multiple functions — a clump traveling together with no name.
Related arguments travel together as one well-named value object that the function (and callers) refer to by name.
Before the refactoring
function recordTemperature(low, high, value) { /* ... */ }function alertIfOutOfRange(low, high, reading) { /* ... */ }
After the refactoring
class NumberRange {constructor(low, high) { this.low = low; this.high = high; }}function recordTemperature(range, value) { /* ... */ }function alertIfOutOfRange(range, reading) { /* ... */ }
Adding a field of the clump touches every signature; callers must remember positional order; the clump's identity stays invisible.
Premature parameter objects hide which fields are actually needed by which method — wait until the clump appears in 3+ places before extracting.
Adding a related field is one type change instead of touching every call site; intent is named.
Building parameter objects from coincidental groupings (params that happen to appear together but don't share a domain concept) — adds a class for ceremony without expressing meaning.