Skip to content

Nullish coalescing operator '??' #125

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
127 changes: 66 additions & 61 deletions 1-js/02-first-steps/12-nullish-coalescing-operator/article.md
Original file line number Diff line number Diff line change
@@ -1,93 +1,96 @@
# Nullish coalescing operator '??'
# Toán tử nullish coalescing '??'

[recent browser="new"]

Here, in this article, we'll say that an expression is "defined" when it's neither `null` nor `undefined`.
Toán tử nullish coalescing được viết dưới dạng hai dấu hỏi `??`.

The nullish coalescing operator is written as two question marks `??`.
Do toán tử này coi `null` và `undefined` như nhau, chúng ta sẽ dùng một thuật ngữ đặc biệt ở bài này. Chúng ta sẽ nói rằng một biểu thức được coi là "được định nghĩa" khi nó không phải là `null` hoặc `undefined`.
Comment on lines +5 to +7
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • Cần đảo lại thứ tự 2 đoạn này để đúng với bản gốc.
  • Do toán tử này coi nullundefined như nhau, chúng ta sẽ dùng một thuật ngữ đặc biệt ở bài này. => Câu này cung cấp thêm thông tin nhưng nó không có trong bản gốc. Liệu nên giữ nó lại hay bỏ đi?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

em thấy là ở bản gốc tiếng anh có thay đổi khác với bản hiện tại tiếng việt nên em đã dịch theo bản mới luôn ạ.
https://javascript.info/nullish-coalescing-operator

Copy link
Contributor

@tunggnu tunggnu Apr 5, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • Trên nguyên tắc, do bạn fork từ repo của bản tiếng Việt nên cần căn cứ theo bản tiếng Việt để dịch, không nên tham khảo chéo sang repo của bản tiếng Anh dù có thể nó có code mới hơn, nếu không nội dung sẽ không nhất quán, gây hiểu nhầm khi review.
  • Bạn nên tạo riêng một branch ứng với bài viết bạn đang dịch, và chỉ xóa nó sau khi đã merge thành công vào repo bản tiếng Việt, như thế bạn có thể dịch song song nhiều bài viết. Không nên làm việc trực tiếp trên branch master như với bài viết này.
  • Trong quá trình dịch hoặc trước khi bạn tạo pull request bạn có thể update repo của bản tiếng Việt rồi merge sang branch đang dịch để xem các thay đổi mới nhất nếu có, rồi cập nhật bản dịch của bạn nếu cần.

Mình đã update code mới nhất từ repo tiếng Anh sang repo tiếng Việt, do đó pull request này của bạn đã bị conflict. Bạn có thể cập nhật bản dịch này và xử lý conflict nếu muốn.


The result of `a ?? b` is:
- if `a` is defined, then `a`,
- if `a` isn't defined, then `b`.
Kết quả của `a ?? b` là:

- Nếu `a` được định nghĩa, trả về `a`,
- Nếu `a` chưa được định nghĩa, trả về `b`.

In other words, `??` returns the first argument if it's not `null/undefined`. Otherwise, the second one.
Nói một cách khác, `??` trả về đối số đầu tiên nếu nó không có giá trị `null/undefined`. Nếu không thì trả về đối số thứ hai.

The nullish coalescing operator isn't anything completely new. It's just a nice syntax to get the first "defined" value of the two.
Toán tử nullish coalescing không phải là hoàn toàn mới. Nó đơn thuần là một cú pháp ngắn gọn để lấy giá trị đầu tiên "được định nghĩa" trong hai giá trị.

We can rewrite `result = a ?? b` using the operators that we already know, like this:
Chúng ta có viết lại biểu thức `result = a ?? b` sử dụng toán tử khác mà chúng ta đã biết, như sau:

```js
result = (a !== null && a !== undefined) ? a : b;
result = a !== null && a !== undefined ? a : b;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Không sửa phần mã của bản gốc, trừ khi nó là chuỗi kí tự hoặc chú thích.

```

The common use case for `??` is to provide a default value for a potentially undefined variable.
Giờ thì chắc bạn đã biết rõ toán tử `??` làm gì. Hãy xem có thể áp dụng toán tử này ở đâu.

Comment on lines +24 to 25
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Đoạn này không có trong bản gốc.

For example, here we show `Anonymous` if `user` isn't defined:
Use case thường gặp để dùng toán tử `??` là để cung cấp một giá trị mặc định cho một biến số có khả năng là undefined.

Ví dụ, ở đây chúng ta sẽ hiển thị `user` nếu như được định nghĩa, nếu không sẽ hiển thị `Ẩn danh`:

```js run
let user;

alert(user ?? "Anonymous"); // Anonymous
alert(user ?? "Ẩn danh"); // Ẩn danh (user chưa được định nghĩa)
```

Of course, if `user` had any value except `null/undefined`, then we would see it instead:
Còn dưới đây là ví dụ với `user` được gán với một cái tên:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dịch không giống bản gốc.


```js run
let user = "John";

alert(user ?? "Anonymous"); // John
alert(user ?? "Ẩn danh"); // John (user đã được định nghĩa)
```

We can also use a sequence of `??` to select the first value from a list that isn't `null/undefined`.
Chúng ta cũng có thể dùng nhiều toán tử `??` để chọn giá trị đầu tiên trong một danh sách mà không có giá trị là `null/undefined`.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sửa câu này lại như sau liệu có hợp lý hơn?

Chúng ta cũng có thể dùng nhiều toán tử ?? để chọn giá trị đầu tiên không phải là null/undefined trong một danh sách.


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.
Ví dụ chúng ta có một dữ liệu của người dùng trong các biến `firstName`, `lastName` hoặc `nickName`. Tất cả đều có thể chưa được định nghĩa, nếu như người dùng quyết định không nhập vào giá trị.

We'd like to display the user name using one of these variables, or show "Anonymous" if all of them are undefined.
Và chúng ta muốn hiển thị tên người dùng sử dụng một trong các biến này, hoặc hiển thị "Ẩn danh" nếu như tất cả đều chưa được định nghĩa.

Let's use the `??` operator for that:
Hãy sử dụng toán tử `??` cho trường hợp đó:

```js run
let firstName = null;
let lastName = null;
let nickName = "Supercoder";

// shows the first defined value:
// hiển thị giá trị được định nghĩa đầu tiên:
*!*
alert(firstName ?? lastName ?? nickName ?? "Anonymous"); // Supercoder
alert(firstName ?? lastName ?? nickName ?? "Ẩn danh"); // Supercoder
*/!*
```

## Comparison with ||
## So sánh với toán tử ||

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).
Toán tử HOẶC `||` có thể được dùng theo cùng cách với `??`, như cách được mô tả ở [chương trước](info:logical-operators#or-finds-the-first-truthy-value).

For example, in the code above we could replace `??` with `||` and still get the same result:
Ví dụ, ở đoạn code phía trên chúng ta có thể thay thế `??` với `||` và vẫn đạt được cùng kết quả:

```js run
let firstName = null;
let lastName = null;
let nickName = "Supercoder";

// shows the first truthy value:
// hiển thị giá trị truthy đầu tiên:
*!*
alert(firstName || lastName || nickName || "Anonymous"); // Supercoder
alert(firstName || lastName || nickName || "Ẩn danh"); // Supercoder
*/!*
```

The OR `||` operator exists since the beginning of JavaScript, so developers were using it for such purposes for a long time.
Về mặt lịch sử, toán tử HOẶC `||` có trước. Nó tồn tại từ khi Javascript được tạo ra, do vậy lập trình viên đã dùng chúng cho những việc trên từ rất lâu.

Ngược lại, toán tử nullish coalescing `??` mới được thêm vào Javascript gần đây, và lý do là vì mọi người không thực sự hài lòng với toán tử `||`.

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 `||`.
Điểm khác biệt quan trọng giữa cả hai là:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bình thường người ta không hay nói "giữa cả hai" mà chỉ nói "giữa chúng" hoặc "giữa hai toán tử".


The important difference between them is that:
- `||` returns the first *truthy* value.
- `??` returns the first *defined* value.
- `||` trả về giá trị _truthy_ đầu tiên.
- `??` trả về giá trị _được_ _định_ _nghĩa_ đầu tiên.

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.
Nói một cách khác, `||` không phân biệt được giữa `false`, `0`, một chuỗi rỗng `""` `null/undefined`. Chúng đều giống nhau - là các giá trị falsy. Nếu bất cứ giá trị nào trên đây là đối số đầu tiên của toán tử `||`, thì chúng ta sẽ có kết quả là đối số thứ hai.

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.
Tuy nhiên trong thực tiễn, chúng ta thường sẽ chỉ muốn sử dụng giá trị mặc định chỉ khi giá trị là `null/undefined`. Đó là khi giá trị thực sự là không xác định/chưa được set.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Đoạn này hơi lủng củng. Có lẽ nên dịch như sau:

Tuy nhiên trong thực tiễn, chúng ta có thể chỉ muốn sử dụng giá trị mặc định khi biến là null/undefined. Đó là khi giá trị thực sự là không-xác-định/chưa-được-đặt.

Viết theo kiểu "không-xác-định/chưa-được-đặt" sẽ dễ hiểu hơn là viết rời rạc "không xác định/chưa được đặt"


For example, consider this:
Ví dụ, như trường hợp sau:

```js run
let height = 0;
Expand All @@ -96,71 +99,73 @@ alert(height || 100); // 100
alert(height ?? 100); // 0
```

- The `height || 100` checks `height` for being a falsy value, and it really is.
- so the result is the second argument, `100`.
- The `height ?? 100` checks `height` for being `null/undefined`, and it's not,
- so the result is `height` "as is", that is `0`.
- Biểu thức `height || 100` kiểm tra xem `height` có phải là một giá trị falsy không, và đúng là nó có giá trị falsy.
- thế nên kết quả của `||` là đối số thứ hai, `100`.
- Còn biểu thức `height ?? 100` kiểm tra xem `height` có phải là `null/undefined` hay không, và nó không phải,
- thế nên kết quả của biểu thức là `height`, tức là `0`.

Trong thực tiễn, height là 0 thường là một giá trị hợp lệ và không nên thay thế bằng một giá trị mặc định. Vì thế ở đây sử dụng `??` là chính xác.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dịch không giống bản gốc.


If the zero height is a valid value, that shouldn't be replaced with the default, then `??` does just the right thing.
## Thứ tự thực hiện

## Precedence
Thứ tự thực hiện cảu toán tử `??` gần ngang với `||`, chỉ thấp hơn một chút. Nó xếp thứ 5 trong [bảng MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Operator_Precedence#Table), trong khi `||` xếp thứ 6.

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 `+`, `*`.
Điều đó có nghĩa là, giống như `||`, toán tử nullish coaslescing `??` sẽ được đánh giá trước `=` `?`, nhưng sau phần lớn các toán tử khác, ví dụ như `+`, `*`.
Comment on lines +111 to +113
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hai đoạn này tuy không sai nhưng không giống bản gốc nên cần dịch lại để tôn trọng bản gốc.


So if we'd like to choose a value with `??` in an expression with other operators, consider adding parentheses:
Thế nên nếu chúng ta muốn sử dụng `??` trong một biểu thức với các toán tử khác, thì việc cho thêm ngoặc đơn nên được cân nhắc:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Trong tình huống thông thường nên sử dụng câu chủ động thì tốt hơn là câu bị động, ví dụ như:

Thế nên nếu chúng ta muốn sử dụng ?? trong một biểu thức với các toán tử khác, thì nên cân nhắc cho thêm các dấu ngoặc đơn:


```js run
let height = null;
let width = null;

// important: use parentheses
// quan trọng: sử dụng ngoặc đơn
let area = (height ?? 100) * (width ?? 50);

alert(area); // 5000
```

Otherwise, if we omit parentheses, then as `*` has the higher precedence than `??`, it would execute first, leading to incorrect results.
Nếu không, nếu chúng ta bỏ qua ngoặc đơn ở đây, thì do `*` có thứ tự thực hiện cao hơn `??` nên sẽ được thực thi trước, dẫn đến kết quả không chính xác.

```js
// without parentheses
// khi không có ngoặc đơn
let area = height ?? 100 * width ?? 50;

// ...works the same as this (probably not what we want):
// ... hoạt động tương đương như với dòng sau (có lẽ không như chúng ta mong muốn):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hoạt động tương đương như với dòng sau

let area = height ?? (100 * width) ?? 50;
```

### Using ?? with && or ||
### Sử dụng ?? với && hay ||

Due to safety reasons, JavaScript forbids using `??` together with `&&` and `||` operators, unless the precedence is explicitly specified with parentheses.
Vì lý do an toàn, Javascript cấm sử dụng `??` chung với toán tử `&&` `||`, trừ khi thứ tự thực hiện được chỉ rõ với ngoặc đơn.

The code below triggers a syntax error:
Dòng code dưới đây gây ra một syntax error (lỗi cú pháp):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cụm từ "syntax error" trong tình huống này không phải là một thuật ngữ hoặc danh từ riêng được sử dụng nhiều lần trong bài viết, nên nó chỉ có tác dụng ghi chú về mặt dịch thuật. Cho nó vào trong cặp ngoặc đơn có lẽ hợp lý hơn:

Dòng code dưới đây gây ra một lỗi cú pháp (syntax error):


```js run
let x = 1 && 2 ?? 3; // Syntax error
```

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 `||`.
Hạn chế này có gây tranh cãi, tuy nhiên việc này được thêm vào đặc tả của ngôn ngữ với mong muốn tránh được sai lầm khi lập trình, khi mọi người bắt đầu chuyển từ `||` sang `??`.

Use explicit parentheses to work around it:
Sử dụng ngoặc đơn để xử lý tạm thời với vấn đề này:

```js run
*!*
let x = (1 && 2) ?? 3; // Works
let x = (1 && 2) ?? 3; // Hoạt động
*/!*

alert(x); // 2
```

## Summary
## Tổng kết

- The nullish coalescing operator `??` provides a short way to choose the first "defined" value from a list.
- Toán tử nullish coalescing `??` cung cấp một cách ngắn gọn để chọn giá trị đầu tiên "được định nghĩa" trong một danh sách.

It's used to assign default values to variables:
Nó được dùng để gán giá trị mặc định cho biến:

```js
// set height=100, if height is null or undefined
height = height ?? 100;
```
```js
// set height=100, nếu height null hoặc undefined
height = height ?? 100;
```

- The operator `??` has a very low precedence, only a bit higher than `?` and `=`, so consider adding parentheses when using it in an expression.
- It's forbidden to use it with `||` or `&&` without explicit parentheses.
- Toán tử `??` có thứ tự thực hiện rất thấp, chỉ cao hơn `?` `=` một chút, do đó bạn nên cân nhắc thêm ngoặc đơn khi sử dụng nó trong một biểu thức.
- Toán tử này không được phép dùng chung với toán tử `||` hoặc `&&` nếu không có ngoặc đơn được chỉ rõ.