|
| 1 | +# Nullish coalescing operator '??' |
| 2 | + |
| 3 | +[recent browser="new"] |
| 4 | + |
| 5 | +Here, in this article, we'll say that an expression is "defined" when it's neither `null` nor `undefined`. |
| 6 | + |
| 7 | +The nullish coalescing operator is written as two question marks `??`. |
| 8 | + |
| 9 | +The result of `a ?? b` is: |
| 10 | +- if `a` is defined, then `a`, |
| 11 | +- if `a` isn't defined, then `b`. |
| 12 | + |
| 13 | + |
| 14 | +In other words, `??` returns the first argument if it's not `null/undefined`. Otherwise, the second one. |
| 15 | + |
| 16 | +The nullish coalescing operator isn't anything completely new. It's just a nice syntax to get the first "defined" value of the two. |
| 17 | + |
| 18 | +We can rewrite `result = a ?? b` using the operators that we already know, like this: |
| 19 | + |
| 20 | +```js |
| 21 | +result = (a !== null && a !== undefined) ? a : b; |
| 22 | +``` |
| 23 | + |
| 24 | +The common use case for `??` is to provide a default value for a potentially undefined variable. |
| 25 | + |
| 26 | +For example, here we show `Anonymous` if `user` isn't defined: |
| 27 | + |
| 28 | +```js run |
| 29 | +let user; |
| 30 | + |
| 31 | +alert(user ?? "Anonymous"); // Anonymous |
| 32 | +``` |
| 33 | +
|
| 34 | +Of course, if `user` had any value except `null/undefined`, then we would see it instead: |
| 35 | +
|
| 36 | +```js run |
| 37 | +let user = "John"; |
| 38 | + |
| 39 | +alert(user ?? "Anonymous"); // John |
| 40 | +``` |
| 41 | +
|
| 42 | +We can also use a sequence of `??` to select the first value from a list that isn't `null/undefined`. |
| 43 | +
|
| 44 | +Let's say we have a user's data in variables `firstName`, `lastName` or `nickName`. All of them may be undefined, if the user decided not to enter a value. |
| 45 | +
|
| 46 | +We'd like to display the user name using one of these variables, or show "Anonymous" if all of them are undefined. |
| 47 | +
|
| 48 | +Let's use the `??` operator for that: |
| 49 | +
|
| 50 | +```js run |
| 51 | +let firstName = null; |
| 52 | +let lastName = null; |
| 53 | +let nickName = "Supercoder"; |
| 54 | + |
| 55 | +// shows the first defined value: |
| 56 | +*!* |
| 57 | +alert(firstName ?? lastName ?? nickName ?? "Anonymous"); // Supercoder |
| 58 | +*/!* |
| 59 | +``` |
| 60 | +
|
| 61 | +## Comparison with || |
| 62 | +
|
| 63 | +The OR `||` operator can be used in the same way as `??`, as it was described in the [previous chapter](info:logical-operators#or-finds-the-first-truthy-value). |
| 64 | +
|
| 65 | +For example, in the code above we could replace `??` with `||` and still get the same result: |
| 66 | +
|
| 67 | +```js run |
| 68 | +let firstName = null; |
| 69 | +let lastName = null; |
| 70 | +let nickName = "Supercoder"; |
| 71 | + |
| 72 | +// shows the first truthy value: |
| 73 | +*!* |
| 74 | +alert(firstName || lastName || nickName || "Anonymous"); // Supercoder |
| 75 | +*/!* |
| 76 | +``` |
| 77 | +
|
| 78 | +The OR `||` operator exists since the beginning of JavaScript, so developers were using it for such purposes for a long time. |
| 79 | +
|
| 80 | +On the other hand, the nullish coalescing operator `??` was added to JavaScript only recently, and the reason for that was that people weren't quite happy with `||`. |
| 81 | +
|
| 82 | +The important difference between them is that: |
| 83 | +- `||` returns the first *truthy* value. |
| 84 | +- `??` returns the first *defined* value. |
| 85 | +
|
| 86 | +In other words, `||` doesn't distinguish between `false`, `0`, an empty string `""` and `null/undefined`. They are all the same -- falsy values. If any of these is the first argument of `||`, then we'll get the second argument as the result. |
| 87 | +
|
| 88 | +In practice though, we may want to use default value only when the variable is `null/undefined`. That is, when the value is really unknown/not set. |
| 89 | +
|
| 90 | +For example, consider this: |
| 91 | +
|
| 92 | +```js run |
| 93 | +let height = 0; |
| 94 | + |
| 95 | +alert(height || 100); // 100 |
| 96 | +alert(height ?? 100); // 0 |
| 97 | +``` |
| 98 | +
|
| 99 | +- The `height || 100` checks `height` for being a falsy value, and it really is. |
| 100 | + - so the result is the second argument, `100`. |
| 101 | +- The `height ?? 100` checks `height` for being `null/undefined`, and it's not, |
| 102 | + - so the result is `height` "as is", that is `0`. |
| 103 | +
|
| 104 | +If the zero height is a valid value, that shouldn't be replaced with the default, then `??` does just the right thing. |
| 105 | +
|
| 106 | +## Precedence |
| 107 | +
|
| 108 | +The precedence of the `??` operator is rather low: `5` in the [MDN table](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Operator_Precedence#Table). So `??` is evaluated before `=` and `?`, but after most other operations, such as `+`, `*`. |
| 109 | +
|
| 110 | +So if we'd like to choose a value with `??` in an expression with other operators, consider adding parentheses: |
| 111 | +
|
| 112 | +```js run |
| 113 | +let height = null; |
| 114 | +let width = null; |
| 115 | + |
| 116 | +// important: use parentheses |
| 117 | +let area = (height ?? 100) * (width ?? 50); |
| 118 | + |
| 119 | +alert(area); // 5000 |
| 120 | +``` |
| 121 | +
|
| 122 | +Otherwise, if we omit parentheses, then as `*` has the higher precedence than `??`, it would execute first, leading to incorrect results. |
| 123 | +
|
| 124 | +```js |
| 125 | +// without parentheses |
| 126 | +let area = height ?? 100 * width ?? 50; |
| 127 | + |
| 128 | +// ...works the same as this (probably not what we want): |
| 129 | +let area = height ?? (100 * width) ?? 50; |
| 130 | +``` |
| 131 | +
|
| 132 | +### Using ?? with && or || |
| 133 | +
|
| 134 | +Due to safety reasons, JavaScript forbids using `??` together with `&&` and `||` operators, unless the precedence is explicitly specified with parentheses. |
| 135 | +
|
| 136 | +The code below triggers a syntax error: |
| 137 | +
|
| 138 | +```js run |
| 139 | +let x = 1 && 2 ?? 3; // Syntax error |
| 140 | +``` |
| 141 | +
|
| 142 | +The limitation is surely debatable, but it was added to the language specification with the purpose to avoid programming mistakes, when people start to switch to `??` from `||`. |
| 143 | +
|
| 144 | +Use explicit parentheses to work around it: |
| 145 | +
|
| 146 | +```js run |
| 147 | +*!* |
| 148 | +let x = (1 && 2) ?? 3; // Works |
| 149 | +*/!* |
| 150 | + |
| 151 | +alert(x); // 2 |
| 152 | +``` |
| 153 | +
|
| 154 | +## Summary |
| 155 | +
|
| 156 | +- The nullish coalescing operator `??` provides a short way to choose the first "defined" value from a list. |
| 157 | +
|
| 158 | + It's used to assign default values to variables: |
| 159 | +
|
| 160 | + ```js |
| 161 | + // set height=100, if height is null or undefined |
| 162 | + height = height ?? 100; |
| 163 | + ``` |
| 164 | +
|
| 165 | +- The operator `??` has a very low precedence, only a bit higher than `?` and `=`, so consider adding parentheses when using it in an expression. |
| 166 | +- It's forbidden to use it with `||` or `&&` without explicit parentheses. |
0 commit comments