There is no naming convention in JavaScript to differentiate between pure functions and functions with side-effects.
It doesn't mean you shouldn't have one for your project though. I think it is a good idea.
A possible first approach is following the command–query separation principle, that states that only pure functions (queries) return values, while functions with side-effects (commands) do not.
Then you can look at existing languages following a similar convention.
In Scheme
and Ruby
(inspired by Scheme
) functions causing side-effects end in !
(e.g. set-car!
) and predicates end in ?
(e.g. number?
).
From https://www.cs.cmu.edu/Groups/AI/html/r4rs/r4rs_3.html#SEC14:
By convention, the names of procedures that always return a boolean
value usually end in "`?'". Such procedures are called predicates.
By convention, the names of procedures that store values into
previously allocated locations (see section Storage model) usually end
in "`!'". Such procedures are called mutation procedures. By
convention, the value returned by a mutation procedure is unspecified.
Unfortunately you can't use !
and ?
as part of a function name in JavaScript.
In Common Lisp
, predicates end in p
(e.g. EVENP
) and destructive functions start with n
(that stands for non-consing), e.g. REVERSE
vs NREVERSE
. While possible and compact, I don't find this particularly appealing.
Some languages use imperative and past verbs. Think about python's sort
(in-place) vs sorted
(functional).
Swift's API Design Guidelines is explicit about it:
Name functions and methods according to their side-effects
Those without side-effects should read as noun phrases, e.g.
x.distance(to: y)
, i.successor().
Those with side-effects should read as imperative verb phrases, e.g.,
print(x)
, x.sort()
, x.append(y)
.
Name Mutating/nonmutating method pairs consistently. A mutating method
will often have a nonmutating variant with similar semantics, but that
returns a new value rather than updating an instance in-place.
When the operation is naturally described by a verb, use the verb’s
imperative for the mutating method and apply the “ed” or “ing” suffix
to name its nonmutating counterpart.
Mutating: x.sort()
Nonmutating: z = x.sorted()
Mutating: x.append(y)
Nonmutating: z = x.appending(y)
Prefer to name the nonmutating variant using the verb’s past
participle (usually appending “ed”):
/// Reverses `self` in-place. mutating func reverse()
/// Returns a reversed copy of `self`.
func reversed() -> Self
...
x.reverse()
let y = x.reversed()
When adding “ed” is not grammatical because the verb has a direct object, name the nonmutating variant using the verb’s present participle, by appending “ing.”
/// Strips all the newlines from `self`
mutating func stripNewlines()
/// Returns a copy of `self` with all the newlines stripped.
func strippingNewlines() -> String
...
s.stripNewlines()
let oneLine = t.strippingNewlines()
When the operation is naturally described by a noun, use the noun for
the nonmutating method and apply the “form” prefix to name its
mutating counterpart.
Nonmutating: x = y.union(z)
Mutating: y.formUnion(z)
Nonmutating: j = c.successor(i)
Mutating: c.formSuccessor(&i)
All in all, any reasonable convention that fits your library will do, as long as it is applied consistently.