|
| 1 | +# Nullish coalescing operator '??' |
| 2 | + |
| 3 | +[recent browser="new"] |
| 4 | + |
| 5 | +The nullish coalescing operator `??` provides a short syntax for selecting a first "defined" variable from the list. |
| 6 | + |
| 7 | +The result of `a ?? b` is: |
| 8 | +- `a` if it's not `null` or `undefined`, |
| 9 | +- `b`, otherwise. |
| 10 | + |
| 11 | +So, `x = a ?? b` is a short equivalent to: |
| 12 | + |
| 13 | +```js |
| 14 | +x = (a !== null && a !== undefined) ? a : b; |
| 15 | +``` |
| 16 | + |
| 17 | +Here's a longer example. |
| 18 | + |
| 19 | +Let's say, we have a `firstName`, `lastName` or `nickName`, all of them optional. |
| 20 | + |
| 21 | +Let's choose the defined one and show it (or "Anonymous" if nothing is set): |
| 22 | + |
| 23 | +```js run |
| 24 | +let firstName = null; |
| 25 | +let lastName = null; |
| 26 | +let nickName = "Supercoder"; |
| 27 | + |
| 28 | +// show the first not-null/undefined variable |
| 29 | +alert(firstName ?? lastName ?? nickName ?? "Anonymous"); // Supercoder |
| 30 | +``` |
| 31 | +
|
| 32 | +## Comparison with || |
| 33 | +
|
| 34 | +That's very similar to OR `||` operator. Actually, we can replace `??` with `||` in the code above and get the same result. |
| 35 | +
|
| 36 | +The important difference is that: |
| 37 | +- `||` returns the first *truthy* value. |
| 38 | +- `??` returns the first *defined* value. |
| 39 | +
|
| 40 | +This matters a lot when we'd like to treat `null/undefined` differently from `0`. |
| 41 | +
|
| 42 | +For example: |
| 43 | +
|
| 44 | +```js |
| 45 | +height = height ?? 100; |
| 46 | +``` |
| 47 | +
|
| 48 | +This sets `height` to `100` if it's not defined. But if `height` is `0`, then it remains "as is". |
| 49 | +
|
| 50 | +Let's compare it with `||`: |
| 51 | +
|
| 52 | +```js run |
| 53 | +let height = 0; |
| 54 | + |
| 55 | +alert(height || 100); // 100 |
| 56 | +alert(height ?? 100); // 0 |
| 57 | +``` |
| 58 | +
|
| 59 | +Here, `height || 100` treats zero height as unset, same as `null`, `undefined` or any other falsy value, depeding on use cases that may be incorrect. |
| 60 | +
|
| 61 | +The `height ?? 100` returns `100` only if `height` is exactly `null` or `undefined`. |
| 62 | +
|
| 63 | +## Precedence |
| 64 | +
|
| 65 | +The precedence of the `??` operator is rather low: `7` in the [MDN table](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Operator_Precedence#Table). |
| 66 | +
|
| 67 | +That's lower than most operators and a bit higher than `=` and `?`. |
| 68 | +
|
| 69 | +So if we need to use `??` in a complex expression, then consider adding parentheses: |
| 70 | +
|
| 71 | +```js run |
| 72 | +let height = null; |
| 73 | +let width = null; |
| 74 | + |
| 75 | +// important: use parentheses |
| 76 | +let area = (height ?? 100) * (width ?? 50); |
| 77 | + |
| 78 | +alert(area); // 5000 |
| 79 | +``` |
| 80 | +
|
| 81 | +Otherwise, if we omit parentheses, then `*` has the higher precedence and would run first. That would be the same as: |
| 82 | +
|
| 83 | +```js |
| 84 | +// not correct |
| 85 | +let area = height ?? (100 * width) ?? 50; |
| 86 | +``` |
| 87 | +
|
| 88 | +There's also a related language-level limitation. Due to safety reasons, it's forbidden to use `??` together with `&&` and `||` operators. |
| 89 | +
|
| 90 | +The code below triggers a syntax error: |
| 91 | +
|
| 92 | +```js run |
| 93 | +let x = 1 && 2 ?? 3; // Syntax error |
| 94 | +``` |
| 95 | +
|
| 96 | +The limitation is surely debatable, but for some reason it was added to the language specification. |
| 97 | +
|
| 98 | +Use explicit parentheses to fix it: |
| 99 | +
|
| 100 | +```js run |
| 101 | +let x = (1 && 2) ?? 3; // Works |
| 102 | +alert(x); // 2 |
| 103 | +``` |
| 104 | +
|
| 105 | +## Summary |
| 106 | +
|
| 107 | +- The nullish coalescing operator `??` provides a short way to choose a "defined" value from the list. |
| 108 | +
|
| 109 | + It's used to assign default values to variables: |
| 110 | +
|
| 111 | + ```js |
| 112 | + // set height=100, if height is null or undefined |
| 113 | + height = height ?? 100; |
| 114 | + ``` |
| 115 | +
|
| 116 | +- The operator `??` has a very low precedence, a bit higher than `?` and `=`. |
| 117 | +- It's forbidden to use it with `||` or `&&` without explicit parentheses. |
0 commit comments