Update
JavaScript now supports the nullish coalescing operator (??). It returns its right-hand-side operand when its left-hand-side operand is null or undefined, and otherwise returns its left-hand-side operand.
Old Answer
Please check compatibility before using it.
The JavaScript equivalent of the C# null coalescing operator (??) is using a logical OR (||):
Copyvar whatIWant = someString || "Cookies!";
There are cases (clarified below) that the behaviour won't match that of C#, but this is the general, terse way of assigning default/alternative values in JavaScript.
Clarification
Regardless of the type of the first operand, if casting it to a Boolean results in false, the assignment will use the second operand. Beware of all the cases below:
Copyalert(Boolean(null)); // false
alert(Boolean(undefined)); // false
alert(Boolean(0)); // false
alert(Boolean("")); // false
alert(Boolean("false")); // true -- gotcha! :)
This means:
Copyvar whatIWant = null || new ShinyObject(); // is a new shiny object
var whatIWant = undefined || "well defined"; // is "well defined"
var whatIWant = 0 || 42; // is 42
var whatIWant = "" || "a million bucks"; // is "a million bucks"
var whatIWant = "false" || "no way"; // is "false"
Videos
Update
JavaScript now supports the nullish coalescing operator (??). It returns its right-hand-side operand when its left-hand-side operand is null or undefined, and otherwise returns its left-hand-side operand.
Old Answer
Please check compatibility before using it.
The JavaScript equivalent of the C# null coalescing operator (??) is using a logical OR (||):
Copyvar whatIWant = someString || "Cookies!";
There are cases (clarified below) that the behaviour won't match that of C#, but this is the general, terse way of assigning default/alternative values in JavaScript.
Clarification
Regardless of the type of the first operand, if casting it to a Boolean results in false, the assignment will use the second operand. Beware of all the cases below:
Copyalert(Boolean(null)); // false
alert(Boolean(undefined)); // false
alert(Boolean(0)); // false
alert(Boolean("")); // false
alert(Boolean("false")); // true -- gotcha! :)
This means:
Copyvar whatIWant = null || new ShinyObject(); // is a new shiny object
var whatIWant = undefined || "well defined"; // is "well defined"
var whatIWant = 0 || 42; // is 42
var whatIWant = "" || "a million bucks"; // is "a million bucks"
var whatIWant = "false" || "no way"; // is "false"
Copyfunction coalesce() {
var len = arguments.length;
for (var i=0; i<len; i++) {
if (arguments[i] !== null && arguments[i] !== undefined) {
return arguments[i];
}
}
return null;
}
var xyz = {};
xyz.val = coalesce(null, undefined, xyz.val, 5);
// xyz.val now contains 5
this solution works like the SQL coalesce function, it accepts any number of arguments, and returns null if none of them have a value. It behaves like the C# ?? operator in the sense that "", false, and 0 are considered NOT NULL and therefore count as actual values. If you come from a .net background, this will be the most natural feeling solution.
Many languages have a "null-coalescing" operator: a binary operator used to unwrap an optional/nullable value, or provide a "default" value if the LHS is null/none. It's usually spelled ?? (as in Javascript, Swift, C#, etc.).
I'm pondering the precedence of such an operator.
Why not just use no precedence? Parenthesis! S-expressions! Polish!
All interesting ideas! But this post will focus on a more "C-style" language perspective.
As for ??, it seems like there's a bit of variety. Let's start with a kind of basic operator precedence for a hypothetical C-style statically typed language with relatively few operators:
| prec | operators | types |
|---|---|---|
| 1 | Suffixes: a() | -> any type |
| 2 | High-prec arithmetic: a * b | integer, integer -> integer |
| 3 | Low-prec arithmetic: a + b | integer, integer -> integer |
| 4 | Comparisons: a == b | integer, integer -> boolean |
| 5 | Logic: a && b | boolean, boolean -> boolean |
There are subtly differences here and there, but this is just for comparisons. Here's how (some) different languages handle the precedence.
Below #5:
C#
PHP
Dart
Equal to #5
Javascript (Kinda;
??must be disambiguated from&&and||)Between #3 and #4:
Swift
Zig
Kotlin
So, largely 2 camps: very low precedence, or moderately low. From a brief look, I can't find too much information on the "why" of all of this. One thing I did see come up a lot is this: ?? is analogous to ||, especially if they both short-circuit. And in a lot of programming languages with a looser type system, they're the same thing. Python's or comes to mind. Not relevant to a very strict type system, but at least it makes sense why you would put the precedence down that. Score 1 for the "below/equal 5" folk.
However, given the divide, it's certainly not a straightforward problem. I've been looking around, and have found a few posts where people discuss problems with various systems.
https://forums.swift.org/t/nil-coalescing-operator-precedence/2954
https://www.codeproject.com/Tips/721145/Beware-The-null-coalescing-operator-is-low-in-the
These seem to center around this construct: let x = a() ?? 0 + b() ?? 0. Operator precedence is largely cultural/subjective. But if I were a code reviewer, attempting to analyze a programmer's intent, it seems pretty clear to me that the programmer of this wanted x to equal the sum of a() and b(), with default values in case either were null. However, no one parses ?? as having a higher precedence than +.
This example might be a bit contrived. To us, the alternate parse of let x = a() ?? (0 + b()) ?? 0 because... why would you add to 0? And how often are you chaining null coalescing operators? (Well, it can happen if you're using optionals, but it's still rare). But, it's a fairly reasonable piece of code. Those links even have some real-world examples like this people have fallen for.
Looking at this from a types perspective, I came to this conclusion; In a strongly-typed language, operator precedence isn't useful if operators can't "flow" from high to low precedence due to types.
To illustrate, consider the expression x + y ?? z. We don't know what the types of x, y, and z are. However, if ?? has a lower precedence than +, this expression can't be valid in a strictly typed language, where the LHS of ?? must be of an optional/nullable type.
If you look back at our hypothetical start table, you can see how operator types "flow" through precedence. Arithmetic produces integers, which can be used as arguments to comparisons. Comparisons produce booleans, which can be used as arguments to logical operators.
This is why I'd propose that it makes sense for ?? to have a precedence, in our example, between 1 and 2. That way, more "complex" types can "decay" though the precedence chain. Optionals are unwrapped to integers, which are manipulated by arithmetic, decayed to booleans by comparison, and further manipulated by logic.
Discussion questions:
What are some reasons for choosing the precedence of
??other than the ones discussed?Have any other languages done something different with the precedence, and why?
Has anyone put the precedence of
??above arithmetic?
Thanks!
The OR operator || uses the right value if left is falsy, while the nullish coalescing operator ?? uses the right value if left is null or undefined.
These operators are often used to provide a default value if the first one is missing.
But the OR operator || can be problematic if your left value might contain "" or 0 or false (because these are falsy values):
console.log(12 || "not found") // 12
console.log(0 || "not found") // "not found"
console.log("jane" || "not found") // "jane"
console.log("" || "not found") // "not found"
console.log(true || "not found") // true
console.log(false || "not found") // "not found"
console.log(undefined || "not found") // "not found"
console.log(null || "not found") // "not found"
In many cases, you might only want the right value if left is null or undefined. That's what the nullish coalescing operator ?? is for:
console.log(12 ?? "not found") // 12
console.log(0 ?? "not found") // 0
console.log("jane" ?? "not found") // "jane"
console.log("" ?? "not found") // ""
console.log(true ?? "not found") // true
console.log(false ?? "not found") // false
console.log(undefined ?? "not found") // "not found"
console.log(null ?? "not found") // "not found"
While the ?? operator isn't available in current LTS versions of Node (v10 and v12), you can use it with some versions of TypeScript or Node:
The ?? operator was added to TypeScript 3.7 back in November 2019.
And more recently, the ?? operator was included in ES2020, which is supported by Node 14 (released in April 2020).
When the nullish coalescing operator ?? is supported, I typically use it instead of the OR operator || (unless there's a good reason not to).
In short
The Nullish Coalescing Operator ?? distinguishes between:
- nullish values (
null,undefined) - falsey but defined values (
false,0,''etc.)
|| (logical OR) treats both of these the same.
I created a simple graphic to illustrate the relationship of nullish and falsey values in JavaScript:

Further explanation:
let x, y
x = 0
y = x || 'default' // y = 'default'
y = x ?? 'default' // y = 0
As seen above, the difference between the operators ?? and || is that one is checking for nullish values and one is checking for falsey values. However, there are many instances where they behave the same. That is because in JavaScript every nullish value is also falsey (but not every falsey value is nullish).
Using what we learned above we can create a few examples for different behavior:
let y
y = false || 'default' // y = 'default'
y = false ?? 'default' // y = false
y = 0n || 'default' // y = 'default'
y = 0n ?? 'default' // y = 0n
y = NaN || 'default' // y = 'default'
y = NaN ?? 'default' // y = NaN
y = '' || 'default' // y = 'default'
y = '' ?? 'default' // y = ''
Since the new Nullish Coalescing Operator can differentiate between no value and a falsey value, it can be beneficial if you, for example, need to check if there is no string or an empty string. Generally, you probably want to use ?? instead of || most of the time.
Last and also least here are the two instances where they behave the same:
let y
y = null || 'default' // y = 'default'
y = null ?? 'default' // y = 'default'
y = undefined || 'default' // y = 'default'
y = undefined ?? 'default' // y = 'default'