- Notifications
You must be signed in to change notification settings - Fork44
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 ourterms of service andprivacy statement. We’ll occasionally send you account related emails.
Already on GitHub?Sign in to your account
Uh oh!
There was an error while loading.Please reload this page.
Changes fromall commits
File filter
Filter by extension
Conversations
Uh oh!
There was an error while loading.Please reload this page.
Jump to
Uh oh!
There was an error while loading.Please reload this page.
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,93 +1,96 @@ | ||
| #Toán tử nullish coalescing '??' | ||
| [recent browser="new"] | ||
| Toán tử nullish coalescing được viết dưới dạng hai dấu hỏi `??`. | ||
| 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 Contributor There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others.Learn more.
Author There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 ạ. Contributor There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others.Learn more.
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. | ||
| 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`. | ||
| 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. | ||
| Toán tửnullish coalescingkhô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ị. | ||
| 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; | ||
Contributor There was a problem hiding this comment. Choose a reason for hiding this commentThe 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. | ||
| ``` | ||
| 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 Contributor There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others.Learn more. Đoạn này không có trong bản gốc. | ||
| 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 ?? "Ẩn danh"); //Ẩn danh (user chưa được định nghĩa) | ||
| ``` | ||
| Còn dưới đây là ví dụ với `user` được gán với một cái tên: | ||
Contributor There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 ?? "Ẩn danh"); // John (user đã được định nghĩa) | ||
| ``` | ||
| 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`. | ||
Contributor There was a problem hiding this comment. Choose a reason for hiding this commentThe 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ử | ||
| 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ị. | ||
| 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. | ||
| Hãy sử dụng toán tử`??`cho trường hợp đó: | ||
| ```js run | ||
| let firstName = null; | ||
| let lastName = null; | ||
| let nickName = "Supercoder"; | ||
| //hiển thị giá trị được định nghĩa đầu tiên: | ||
| *!* | ||
| alert(firstName ?? lastName ?? nickName ?? "Ẩn danh"); // Supercoder | ||
| */!* | ||
| ``` | ||
| ##So sánh với toán tử || | ||
| 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). | ||
| Ví dụ, ở đoạn codephí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"; | ||
| //hiển thị giá trịtruthyđầu tiên: | ||
| *!* | ||
| alert(firstName || lastName || nickName || "Ẩn danh"); // Supercoder | ||
| */!* | ||
| ``` | ||
| 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ử `||`. | ||
| Điểm khác biệt quan trọng giữa cả hai là: | ||
Contributor There was a problem hiding this comment. Choose a reason for hiding this commentThe 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ử". | ||
| - `||` trả về giá trị _truthy_ đầu tiên. | ||
| - `??` trả về giá trị _được_ _định_ _nghĩa_ đầu tiên. | ||
| 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 `""`và `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. | ||
| 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. | ||
Contributor There was a problem hiding this comment. Choose a reason for hiding this commentThe 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à 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" | ||
| Ví dụ, như trường hợp sau: | ||
| ```js run | ||
| let height = 0; | ||
| @@ -96,71 +99,73 @@ alert(height || 100); // 100 | ||
| alert(height ?? 100); // 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. | ||
Contributor There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others.Learn more. Dịch không giống bản gốc. | ||
| ## Thứ tự thực hiện | ||
| 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. | ||
| Điều đó có nghĩa là, giống như `||`, toán tử nullish coaslescing`??`sẽ được đánh giá trước`=`và `?`,nhưng sau phần lớn các toán tử khác, ví dụ như `+`, `*`. | ||
Comment on lines +111 to +113 Contributor There was a problem hiding this comment. Choose a reason for hiding this commentThe 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. | ||
| 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: | ||
Contributor There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 | ||
| ```js run | ||
| let height = null; | ||
| let width = null; | ||
| //quan trọng: sử dụng ngoặc đơn | ||
| let area = (height ?? 100) * (width ?? 50); | ||
| alert(area); // 5000 | ||
| ``` | ||
| 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 | ||
| //khi không có ngoặc đơn | ||
| let area = height ?? 100 * width ?? 50; | ||
| // ... hoạt động tương đương như với dòng sau (có lẽ không như chúng ta mong muốn): | ||
Contributor There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others.Learn more. hoạt động tương đương | ||
| let area = height ?? (100 * width) ?? 50; | ||
| ``` | ||
| ###Sử dụng??với &&hay || | ||
| Vì lý do an toàn, Javascript cấm sử dụng`??`chung với toán tử`&&`và `||`, trừ khi thứ tự thực hiện được chỉ rõ với ngoặc đơn. | ||
| Dòng codedưới đây gây ra mộtsyntax error (lỗi cú pháp): | ||
Contributor There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 | ||
| ``` | ||
| 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 `??`. | ||
| 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; //Hoạt động | ||
| */!* | ||
| alert(x); // 2 | ||
| ``` | ||
| ##Tổng kết | ||
| -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. | ||
| Nó được dùng để gán giá trị mặc định cho biến: | ||
| ```js | ||
| // set height=100,nếu heightlà nullhoặc undefined | ||
| height = height ?? 100; | ||
| ``` | ||
| -Toán tử `??`có thứ tự thực hiện rất thấp, chỉ cao hơn `?`và `=` 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õ. | ||