Toán tử Nullish Coalescing là một toán tử logic mới trong JavaScript được giới thiệu trong ES 2020. Trong bài viết này, chúng ta sẽ tìm hiểu cách thức hoạt động của toán tử này.
Có hơn bốn toán tử logic trong JavaScript: AND &&, OR ||, NOT ! và Toán tử kết hợp Nullish ??.
Đôi khi chúng còn được gọi chung là Toán tử Nullish, toán tử này được sử dụng giữa hai toán hạng:
operand1 ?? operand2
Để hiểu toán tử này, chúng ta phải hiểu "nullish", "coalescing" và " short-circuiting " có nghĩa là gì. Bạn có thể đọc thêm các tài liệu bên ngoài để nắm thêm thông tin chi tiết nhé.
Giá trị "nullish" là gì?
Giá trị Nullish trong JavaScript là null và undefined. Những giá trị này thuộc giá trị falsy nhưng được gọi cụ thể hơn là giá trị null. Tất cả các giá trị nullish đều là falsy, nhưng không phải tất cả các giá trị falsy (ví dụ: 0) đều là nullish.
Vì vậy, toán tử nullish có liên quan đến các giá trị null và undefined trong khi các toán tử logic khác có liên quan đến các giá trị truthy và falsy nói chung.
Coalescing và Short - Circuiting
1. Coalescing là gì?
Coalescing theo từ điển có nghĩa là "hợp nhất lại thành một khối". Điều này áp dụng như thế nào trong lập trình? Nó có nghĩa là bạn tập hợp nhiều giá trị lại với nhau để tạo thành một giá trị từ đó.
Coalescing trong lập trình không có nghĩa cụ thể là "ghép các giá trị lại với nhau", mà là "quyết định giá trị nào được tạo ra từ các giá trị được cung cấp".
Chúng ta sẽ xem cách thức hoạt động của nó với các ví dụ ở phần sau trong bài viết này.
2. Circuiting là gì?
Khái niệm Circuiting hay ngắt mạch được áp dụng cho nhiều ngôn ngữ lập trình. Nó xảy ra khi trình thông dịch thực thi một biểu thức liên quan đến boolean và bỏ qua phần không liên quan của biểu thức.
Ví dụ, một biểu thức boolean như "Tôi 30 tuổi và tôi làm trong ngành công nghệ". Biểu thức này sẽ chỉ là true nếu tôi 30 tuổi và không chỉ vậy, tôi còn làm trong ngành công nghệ.
Sau khi trình thông dịch thực thi "Tôi 30 tuổi", nó vẫn chưa thể kết luận rằng toàn bộ biểu thức là đúng, bởi vì trong trường hợp "Tôi KHÔNG làm trong ngành công nghệ", biểu thức sẽ sai. Phần thứ hai của biểu thức có liên quan vì nó có thể thay đổi kết quả.
Nhưng, trong trường hợp "Tôi KHÔNG 30 tuổi", ngắt mạch sẽ xảy ra. Vì phần đầu tiên của biểu thức trả về false, trình thông dịch biết rằng không có ích gì khi đánh giá biểu thức thứ hai. Phần thứ hai không liên quan, vì giá trị từ biểu thức này không làm thay đổi kết quả. Vì vậy, trình thông dịch sẽ bỏ qua phần thứ hai (do đó tiết kiệm tài nguyên - thời gian, năng lượng).
Điều này cũng áp dụng cho toán tử nullish.
Cách thức hoạt động của toán tử Nullish
Bây giờ chúng ta đã xem xét các nguyên tắc cơ bản của toán tử này, hãy cùng tìm hiểu xem toán tử này hoạt động như thế nào.
Khi được sử dụng trong một biểu thức, Toán tử Nullish sẽ kiểm tra toán hạng đầu tiên (bên trái) để xem giá trị của nó là null hay undefined. Nếu không phải, toán tử sẽ trả về nó từ biểu thức. Nhưng nếu toán hạng đầu tiên là bất kỳ giá trị nào trong số đó, toán tử sẽ trả về toán hạng thứ hai từ biểu thức.
Hãy xem một ví dụ nhanh:
function expression1() { return null
} const expression2 = 4 * 5 const result = expression1() ?? expression2 console.log(result)
// 20
Ở đây, chúng ta có một hàm có tên biểu thức1 mà khi được gọi sẽ trả về null. Và chúng ta cũng có biểu thức2 chứa giá trị từ biểu thức 4 * 5.
Đối với biến result, chúng ta sử dụng toán tử nullish và truyền biểu thức1() và biểu thức2 làm toán hạng.
Toán hạng đầu tiên (biểu thức gọi hàm) trả về null. Toán tử xác nhận rằng toán hạng đầu tiên là null, vì vậy nó trả về giá trị từ biểu thức thứ hai: biểu thức2.
Hãy xem một ví dụ khác:
function expression1() { console.log("expression1") return false
} function expression2() { console.log("expression2") return "Dillion"
} const result = expression1() ?? expression2() console.log(result)
// expression1
// false
Ở đây, chúng ta có biểu thức1, một hàm mà khi được gọi sẽ thực thi console.log("biểu thức1"), sau đó trả về false. Và chúng ta có biểu thức2, là một hàm mà khi được gọi, sẽ thực thi console.log("biểu thức2") và trả về "Dillion".
Sử dụng toán tử nullish, chúng ta có toán hạng đầu tiên là biểu thức1() và toán hạng thứ hai là biểu thức2() và gán giá trị từ biểu thức cho result.
Khi chúng ta chạy đoạn mã này, bạn sẽ thấy rằng chúng ta đã ghi nhật ký "biểu thức1", là các lệnh gọi từ việc thực thi biểu thức1. Và bạn thấy rằng result được ghi nhật ký là false. Điều này có nghĩa là, biểu thức1() là biểu thức được trả về từ toán tử nullish.
Toán tử kiểm tra xem biểu thức đầu tiên có trả về null hay undefined hay không, đối với biểu thức đó, nó sẽ trả về biểu thức thứ hai. Nhưng trong trường hợp này, biểu thức đầu tiên trả về false, do đó, toán tử sẽ trả về biểu thức đầu tiên.
Một điều nữa bạn nhận thấy là "biểu thức2" không được ghi lại. Điều này có nghĩa là biểu thức2() hoàn toàn không được thực thi. Ngắt mạch xảy ra ở đây.
Vì toán tử đã xác nhận rằng toán hạng đầu tiên KHÔNG phải là null hoặc undefined, nên nó không bận tâm đến biểu thức thứ hai, vì giá trị của biểu thức thứ hai không làm thay đổi những gì toán tử sẽ trả về.
So sánh toán tử Nullish và OR
Toán tử Nullish và OR có một số điểm tương đồng, nhưng chúng hoạt động hơi khác một chút.
Toán tử OR kiểm tra xem toán hạng đầu tiên có phải là giá trị truthy hay không. Nếu toán hạng đầu tiên là một, nó sẽ trả về nó, ngược lại, nó sẽ trả về toán hạng thứ hai.
Nhưng, toán tử Nullish kiểm tra xem toán hạng đầu tiên có phải là giá trị nullish hay không. Nếu toán hạng đầu tiên không phải là một, nó sẽ trả về nó, ngược lại, nó sẽ trả về toán hạng thứ hai
Dưới đây là ví dụ về OR:
const expression1 = ""
const expression2 = "Dillion" const result = expression1 || expression2 console.log(result)
// "Dillion"
Vì toán hạng đầu tiên, biểu thức1, là một giá trị falsy (chuỗi rỗng), toán tử trả về toán hạng thứ hai. Nếu biểu thức1 là 20, chẳng hạn (là một giá trị truthy), nó sẽ được trả về và ngắt mạch sẽ xảy ra.
Dưới đây là ví dụ về Nullish:
const expression1 = undefined
const expression2 = "Dillion" const result = expression1 ?? expression2 console.log(result)
// "Dillion"
Sử dụng toán tử nullish ở đây, toán hạng đầu tiên là undefined, một giá trị nullish, vì vậy toán tử trả về toán hạng thứ hai. Nếu biểu thức1 là false, 20 hoặc một số giá trị khác không phải nullish, nó sẽ được trả về và ngắt mạch sẽ xảy ra.
Sử dụng toán tử nullish trực tiếp với AND / OR
Bạn có thể trộn trực tiếp các toán tử AND và OR trong các biểu thức nhưng bạn không thể làm điều đó đối với toán tử nullish. Ý tôi là đây:
exp1 && exp2 || exp3 && exp4
Ở đây, chúng tôi kết hợp AND và OR. Thứ tự trong biểu thức này là:
- "biểu thức 1 AND biểu thức 2"
- "kết quả của OR biểu thức 3 đó"
- "kết quả của AND biểu thức 4 đó"
Đừng quên rằng do ngắt mạch, bước 2 hoặc bước 3 có thể không bao giờ đạt được.
Nhưng bạn không thể kết hợp trực tiếp những thứ này với toán tử nullish. Ví dụ:
exp1 && exp2 ?? exp3 || exp4
Chúng tôi đang trộn lẫn AND, Nullish và OR ở đây: điều này sẽ gây ra lỗi cú pháp. Hãy xem một ví dụ thực tế:
function expression1() { return null
} const expression2 = 20 < 10 const expression3 ="Dillion" const result = expression1() ?? expression2 || expression3
// SyntaxError: Unexpected token '||'
Chúng ta có biểu thức1 một hàm mà khi được gọi sẽ trả về null, biểu thức2 chứa giá trị được trả về từ 20 <10 và biểu thức3 chứa giá trị chuỗi "Dillion".
Sử dụng các toán tử nullish và OR với ba biểu thức này, điều tôi mong đợi là:
- biểu thức1() trả về null, vì vậy toán tử nullish trả về phía bên phải của biểu thức là biểu thức2 || biểu thức3
- ở phía bên phải, toán tử OR được sử dụng, toán tử này kiểm tra xem phía bên trái, biểu thức2 có phải là truthy hay không; vì nó là một giá trị falsy, toán tử trả về phía bên phải
Nhưng, bằng cách thực hiện việc này, chúng tôi gặp lỗi: SyntaxError: Dấu '||' không mong đợi. Điều này có nghĩa là bạn không thể sử dụng trực tiếp các toán tử này. Cách duy nhất để kết hợp chúng là thêm dấu ngoặc đơn như thế này:
const result = (expression1() ?? expression2) || expression3 console.log(result)
// Dillion
Bằng cách bao quanh biểu thức1() ?? biểu thức2 bằng dấu ngoặc đơn, sau đó chúng ta có thể sử dụng kết quả được trả về làm toán hạng đầu tiên cho toán tử OR và thêm biểu thức3 làm toán hạng thứ hai.
Tổng kết
Toán tử nullish rất hữu ích trong việc khai báo các giá trị mặc định cho các giá trị null hoặc undefined tiềm năng. Giả sử, bạn đang mong đợi một đối tượng từ API. Nếu đối tượng đó không chứa một thuộc tính được mong đợi, thuộc tính đó có thể chứa null hoặc là undefined như thế này:
const obj = {} console.log(obj.type)
// undefined
Sử dụng toán tử nullish, chúng ta có thể cung cấp một giá trị mặc định:
const obj = {} console.log(obj.type ?? "default")
// "default"
Có nhiều cách khác mà bạn có thể sử dụng toán tử này cho các giá trị mặc định hoặc kiểm tra an toàn.
Cảm ơn các bạn đã theo dõi.