Overusing anonymous functions
Anonymous functions are commonly used to tidy up callback-heavy JS. They can help reduce visual noise, and allow you to avoid coming up with names for trivial snippets of logic.
// This code filters out the "null" items in a list,// then multiplies each element by 2.array .filter(function notNull(x) { return x !== null; }) .map(function double(x) { return x * 2; });
// This does the same, but the functions are anonymousarray .filter(x => x !== null) .map(x => x * 2);
Anonymous functions are often arrow functions too. Arrow functions themselves aren't necessarily nameless in practice though: most environments these days are clever enough to use the assigned variable name.
// A named arrow function.// The variable name "double" is used as the function name.let double = x => x * 2;console.log(double.name);
"double"
Stack traces
Anonymous functions come with their downsides. Stack traces are easier to read when the functions have names. For example:
const doSomething = () => { throw new Error("oh no");};setTimeout(doSomething);
Error: oh no
at doSomething (stackTraceExample.js:2)
Note that the function name doSomething
helpfully appears in the error output. Without a name, you'd have to rely on other clues, like the filename.
setTimeout(() => { throw new Error("oh no");});
Error: oh no
at stackTraceExample.js:2
Things get especially hairy when lots of files have the same name. Errors become harder to track down than they have to be: this example could be line 12 of any index.js
file.
RangeError: invalid array length
at index.js:12
Faced with any of these stack traces, you'd surely be able to track down the offending code with enough time and patience. But the more clues you leave for yourself, the less stressful that process has to be.
Anonymous React components
Here's another anonymous code pattern you might have seen if you use React.
import React from "react";export default () => <p>Hello world</p>;
This may look clean, but components declared this way show up as Anonymous
or _default
in React Dev Tools. That means you can't search for them, and making sense of the tree becomes tricky. Your component tree ends up looking like this...
_default
_default
_default
Anonymous
...
...instead of the much more understandable alternative.
Stack
Box
Card
Avatar
...
Keep your component tree looking more like the second example by naming your components, and React Dev Tools will be your friend rather than another enemy.
Are anonymous functions always bad then?
Not necessarily. I wouldn't argue against the example up at the top of this post. It's easier to read, not much is likely to go wrong with map(x => x * 2)
. The downsides to that particular tradeoff aren't that compelling.
Sometimes alternative labels are available for functions beyond their name. For example, many JS testing frameworks encourage code like this:
test("should return true", () => { assert.equal(doThing(), true);});
The function itself is anonymous, but the test still has a label that will show up if there's an error.
Anonymous functions are everywhere, and they have their place, for better or worse. But we should be aware of their costs too. We're human, and all but the most trivial functions are subject to bugs. So lean towards using named functions instead when in doubt, and maybe you'll help your future self out.