Skip to content

Commit 5c388dd

Browse files
committed
content
1 parent 75680ee commit 5c388dd

File tree

1 file changed

+74
-36
lines changed
  • 1-js/02-first-steps/12-nullish-coalescing-operator

1 file changed

+74
-36
lines changed

1-js/02-first-steps/12-nullish-coalescing-operator/article.md

Lines changed: 74 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -2,56 +2,92 @@
22

33
[recent browser="new"]
44

5-
The nullish coalescing operator `??` provides a short syntax for selecting a first "defined" variable from the list.
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 `??`.
68

79
The result of `a ?? b` is:
8-
- `a` if it's not `null` or `undefined`,
9-
- `b`, otherwise.
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 defined. Otherwise, the second one.
1015

11-
So, `x = a ?? b` is a short equivalent to:
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:
1219

1320
```js
14-
x = (a !== null && a !== undefined) ? a : b;
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
1532
```
1633
17-
Here's a longer example.
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+
```
1841
19-
Imagine, we have a user, and there are variables `firstName`, `lastName` or `nickName` for their first name, last name and the nick name. All of them may be undefined, if the user decided not to enter any value.
42+
We can also use a sequence of `??` to select the first defined value from a list.
2043
21-
We'd like to display the user name: one of these three variables, or show "Anonymous" if nothing is set.
44+
Let's say we 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.
2245
23-
Let's use the `??` operator to select the first defined one:
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:
2449
2550
```js run
2651
let firstName = null;
2752
let lastName = null;
2853
let nickName = "Supercoder";
2954

30-
// show the first not-null/undefined value
55+
// shows the first defined value:
3156
*!*
3257
alert(firstName ?? lastName ?? nickName ?? "Anonymous"); // Supercoder
3358
*/!*
3459
```
3560
3661
## Comparison with ||
3762
38-
The OR `||` operator can be used in the same way as `??`. Actually, we can replace `??` with `||` in the code above and get the same result, as it was described in the [previous chapter](info:logical-operators#or-finds-the-first-truthy-value).
39-
40-
The important difference is that:
41-
- `||` returns the first *truthy* value.
42-
- `??` returns the first *defined* value.
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).
4364
44-
This matters a lot when we'd like to treat `null/undefined` differently from `0`.
65+
For example, in the code above we could replace `??` with `||` and still get the same result:
4566
46-
For example, consider this:
67+
```js run
68+
let firstName = null;
69+
let lastName = null;
70+
let nickName = "Supercoder";
4771

48-
```js
49-
height = height ?? 100;
72+
// shows the first truthy value:
73+
*!*
74+
alert(firstName || lastName || nickName || "Anonymous"); // Supercoder
75+
*/!*
5076
```
5177
52-
This sets `height` to `100` if it's not defined.
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 only recently, and the reason for that was that people weren't quite happy with `||`.
5381
54-
Let's compare it with `||`:
82+
The subtle, yet important difference 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:
5591
5692
```js run
5793
let height = 0;
@@ -60,19 +96,20 @@ alert(height || 100); // 100
6096
alert(height ?? 100); // 0
6197
```
6298
63-
Here, `height || 100` treats zero height as unset, same as `null`, `undefined` or any other falsy value. So the result is `100`.
99+
Here, we have a zero height.
64100
65-
The `height ?? 100` returns `100` only if `height` is exactly `null` or `undefined`. So the `alert` shows the height value `0` "as is".
101+
- The `height || 100` checks `height` for being a falsy value, and it really is.
102+
- so the result is the second argument, `100`.
103+
- The `height ?? 100` checks `height` for being `null/undefined`, and it's not,
104+
- so the result is `height` "as is", that is `0`.
66105
67-
Which behavior is better depends on a particular use case. When zero height is a valid value, then `??` is preferrable.
106+
If we assume that zero height is a valid value, that shouldn't be replaced with the default, then `??` does just the right thing.
68107
69108
## Precedence
70109
71-
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).
72-
73-
So `??` is evaluated after most other operations, but before `=` and `?`.
110+
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 `+`, `*`.
74111
75-
If we need to choose a value with `??` in a complex expression, then consider adding parentheses:
112+
So if we'd like to choose a value with `??` an expression with other operators, consider adding parentheses:
76113
77114
```js run
78115
let height = null;
@@ -84,26 +121,27 @@ let area = (height ?? 100) * (width ?? 50);
84121
alert(area); // 5000
85122
```
86123
87-
Otherwise, if we omit parentheses, `*` has the higher precedence than `??` and would run first.
88-
89-
That would work be the same as:
124+
Otherwise, if we omit parentheses, then as `*` has the higher precedence than `??`, it would execute first, leading to incorrect results.
90125
91126
```js
92-
// probably not correct
127+
// without parentheses
128+
let area = height ?? 100 * width ?? 50;
129+
130+
// ...works the same as this (probably not what we want):
93131
let area = height ?? (100 * width) ?? 50;
94132
```
95133
96-
There's also a related language-level limitation.
134+
### Using ?? with && or ||
97135
98-
**Due to safety reasons, it's forbidden to use `??` together with `&&` and `||` operators.**
136+
Due to safety reasons, JavaScript forbids using `??` together with `&&` and `||` operators, unless the precedence is explicitly specified with parentheses.
99137
100138
The code below triggers a syntax error:
101139
102140
```js run
103141
let x = 1 && 2 ?? 3; // Syntax error
104142
```
105143
106-
The limitation is surely debatable, but it was added to the language specification with the purpose to avoid programming mistakes, as people start to switch to `??` from `||`.
144+
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 `||`.
107145
108146
Use explicit parentheses to work around it:
109147
@@ -126,5 +164,5 @@ alert(x); // 2
126164
height = height ?? 100;
127165
```
128166
129-
- The operator `??` has a very low precedence, a bit higher than `?` and `=`.
167+
- The operator `??` has a very low precedence, a bit higher than `?` and `=`, so consider adding parentheses when using it in an expression.
130168
- It's forbidden to use it with `||` or `&&` without explicit parentheses.

0 commit comments

Comments
 (0)