There seems to be a huge aversion to creating a function in JS. This aversion
causes people try to be clever and use ridiculous tricks just to keep
stuff in one line like a function call would have been. Of course the function
name in a call acts as extra documentation too. We cannot attach a comment
to a tricky expression because then it would defeat the point of doing it
so we just call it "js idiom" and suddenly it is understandable.
Javascript is extremely accessible, most people don't eat specifications for breakfast like
we do. So they will never understand what the hidden assumptions and edge cases
of an idiom is.
x = x || 'default_value';
The average joe will either not understand this or has memorized that it is the idiom for default value. Both are harmful, in fact the latter is even more harmful. He
will not understand the assumptions and edge cases here. He will not care to read the specification
and understand it ever.
When I look at that code I see "if it's null
or undefined
, then set it to this default value. Although
it will also implicitly treat +0
, -0
, NaN
, false
, and ""
as not suitable values. I will have to
remember that 3 months from now when that needs to change. I will probably forget it.".
The implicit assumption is extremely likely to cause a bug in the future and when your codebase is full of tricks like
this then there is no chance you are keeping them all in your head whenever you are thinking about what
a modification will affect. And this is for the "JS pro", the average joe would have written
the bug even if the requirements were to accept a falsy value to begin with.
Your new snippet has more familiar syntax but still has the above problem.
You can go with:
function f(x) {
x = valueOrDefault(x, "default_value");
}
Now you can have very complex logic to handle the edge cases and the client code still looks beautiful and readable.
Now, how do you differentiate between advanced language feature like passing a function as argument or a clever trick
like || "default"
?
Clever tricks are always operating under some hidden assumptions that could be ignored when the code was initially created. I will
never have to modify an IIFE to something else because a requirement changed, it will always be there. Maybe in 2020 when I can use
actual modules but yeah.
| 0
or the cargo cult version ~~num
used for flooring assumes positive and 32-bit signed integer bounds.
|| "default"
assumes all falsy values are same as not passing an argument at all.
And so on.