function f(input) {
const val = input || 1;
return 41 + val;
}
function g(input) {
const val = input ?? 1;
return 41 + val;
}
console.log("using ||:", f(0));
console.log("using ??:", g(0));
The null(ish) coalescing operator only works with null
and undefined
. So, use the null(ish) coalescing operator when you don't want those values but you will otherwise accept other falsy values:
console.log(null ?? "nullish");
console.log(undefined ?? "nullish");
console.log("" ?? "nullish");
console.log(0 ?? "nullish");
console.log(false ?? "nullish");
The logical OR will skip over any falsy value and give you the other thing.
The logical OR will skip over any falsy value and give you the other parameter. This does work and is by now idiomatic, however it is not always what you want:
console.log(null || "falsy");
console.log(undefined || "falsy");
console.log("" || "falsy");
console.log(0 || "falsy");
console.log(false || "falsy");
Here are few rules for how to determine which one you need. The simplest tests:
- do you only want to protect against
null
(and undefined
- it's usually the same thing)? Then use ??
. If you aren't sure, it's probably a good idea to default to the nullish coalescing operator.
- do you know you also don't want
0
or ""
, for example? Then use ||
.
The second one is where it actually gets trickly. How do you know you need to discard falsy values? Well, the very first snippet shows what happens if you do that: f(0)
will discard the zero and thus produce a different result. This is a somewhat common source of bugs. Since the construct a = b || c
is common to introduce a fallback value (in this case c
) it might accidentally fall back to it when you didn't mean to.
function updateAge(years) {
var yearsToAdd = years || 1;
return this.age + yearsToAdd
}
This works if you want to provide a fallback for calling updateAge()
(no argument) but fails if you call updateAge(0)
(no update). Similarly, you could have:
function sayMyName(greeting) {
var prefix = greeting || "Hello, my name is ";
return prefix + this.firstName;
}
Again, this works for sayMyName()
(no argument) but fails for sayMyName("")
(explicitly no greeting).
To generalise, if you are providing a fallback value that's different to the falsy value, then you might have a problem. However, if your fallback is the falsy value - num || 0
or str || ""
then it doesn't really matter.
It's rare (or should be) that you might expect a mixed type (number, or string, or object, etc) and provide a fallback to it: input || fallback
is valid but will reject empty strings and zeroes. It's usually going to be wrong unless you explicitly don't want any of those.
To put it simply, you should likely use the nullish coalescing operator ??
at all times. It will be less cognitive load to figure out whether it's a potential bug or not. There is also not much reason to avoid it. It's newer than the boolean OR, so it doesn't work on older environments, that's true, however nowadays you should likely be transpiling your code for those. If you cannot or prefer not to, then you don't have a choice and should use the boolean OR.