1. Toán tử AND và OR không chỉ trả về Boolean
Thực tế, toán tử && và || sẽ trả về giá trị của một trong các toán hạng, không nhất thiết phải là giá trị Boolean.
1.1 Nguyên lý hoạt động toán tử AND
Toán tử && trả về giá trị “falsy” đầu tiên. Nếu không có giá trị “falsy”, trả về giá trị cuối cùng.
Ví dụ:
// Trả về falsy đầu tiên
false && true; // false
0 && 1; // 0
"" && null; // ""
5 && NaN && 6; // NaN
// Không có falsy, trả về giá trị cuối cùng
6 && 8; // 8
["Red", "Blue"] && { name: "John" } && "Hello"; // "Hello"
true && 1 && "Hello" && ["Red", "Green"]; // ["Red", "Green"]
Tại sao lại có nguyên lý này?: Toán tử && được dùng để kiểm tra tất cả điều kiện đều đúng. Vì vậy, chỉ cần gặp điều kiện sai đầu tiên là có thể kết luận biểu thức là sai. Trả về giá trị “falsy” đầu tiên để phục vụ if kiểm tra và tiết kiệm tài nguyên (không cần kiểm tra các điều kiện còn lại).
Ví dụ 1: Kiểm tra obj là Object và không phải null.
let obj = { key: "value" };
if (obj && typeof obj === "object") {
console.log("Là Object"); // Kết quả được in ra
} else {
console.log("Không phải là Object");
}
Trường hợp này, obj && typeof obj === "object" trả về true. Lệnh if nhận được true và khối lệnh if được thực thi.
Ví dụ 2: Xét trường hợp obj = null.
let obj = null;
if (obj && typeof obj === "object") {
console.log("Là Object");
} else
console.log("Không phải là Object"); // Kết quả được in ra
}
Do obj là null (falsy), toán tử && sẽ ngay lập tức trả về null. Lệnh if nhận được null (falsy) nên khối lệnh else được thực thi.
1.2 Nguyên lý hoạt động toán tử OR
Trả về giá trị “truthy” đầu tiên. Nếu không có giá trị “truthy”, trả về giá trị cuối cùng.
// Trả về truthy đầu tiên
1 || 0; // 1
"Hello" || ""; // "Hello"
"Hi" || "Hello"; // "Hi"
10 || "Hello" || true; // 10
// Không có truthy, trả về giá trị cuối cùng
0 || NaN; // NaN
"" || 0 || null; // null
NaN || -0 || undefined || false; // false
Tại sao lại có nguyên lý này?: Toán tử || được dùng để kiểm tra ít nhất có một điều kiện đều đúng. Vì vậy, chỉ cần gặp điều kiện đúng đầu tiên là có thể kết luận biểu thức là đúng. Trả về giá trị “truthy” đầu tiên để phục vụ if kiểm tra và tiết kiệm tài nguyên (không cần kiểm tra các điều kiện còn lại).
Ví dụ 1: Kiểm tra có firstName hoặc lastName.
let firstName = "";
let lastName = "Nguyen Van A";
if (firstName || lastName) {
console.log("Có tên"); // Kết quả được in ra
} else {
console.log("Không có tên");
}
Trường hợp này, firstName || lastName trả về "Nguyen Van A". Lệnh if nhận được "Nguyen Van A" (truthy) nên khối lệnh if được thực thi.
Ví dụ 2: Xét trường hợp “Không có tên”.
let firstName = "";
let lastName = "";
if (firstName || lastName) {
console.log("Có tên");
} else {
console.log("Không có tên"); // Kết quả được in ra
}
Lúc này, kết quả biểu thức firstName || lastName trả về "" (chuỗi rỗng). Lệnh if nhận được "" (falsy) nên khối lệnh else được thực thi.
2. “Đánh giá ngắn gọn” là gì?
Đánh giá ngắn gọn (Short-Circuit Evaluation) là khi có thể biết kết quả cuối cùng mà không cần xem xét hết biểu thức, quá trình kiểm tra sẽ dừng và trả về kết quả. Điều này giúp tránh làm công việc thừa, giúp tối ưu hơn vì xử lý trở nên nhanh hơn.
Có hai loại “Đánh giá ngắn gọn”:
- Toán tử && (AND): Nếu biểu thức bên trái là “falsy”, toàn bộ biểu thức sẽ trả về giá trị của biểu thức bên trái mà không cần đánh giá biểu thức bên phải.
- Toán tử || (OR): Nếu biểu thức bên trái là “truthy”, toàn bộ biểu thức sẽ trả về giá trị của biểu thức bên trái mà không cần đánh giá biểu thức bên phải.
2.1 Áp dụng “Đánh giá ngắn gọn”
Để áp dụng được lợi ích từ “Đánh giá ngắn gọn”, lập trình viên cần am hiểu tính chất này của toán tử && và || trong JavaScript.
Ví dụ 1: Không tận dụng được lợi ích từ “Đánh giá ngắn gọn”.
let obj = null;
if (typeof obj === "object" && obj) {
console.log("Là Object");
} else
console.log("Không phải là Object"); // Kết quả được in ra
}
Cách viết này chưa tối ưu: Vì typeof obj === "object" trả về true cho cả null, nên dù obj là null, điều kiện obj vẫn được đánh giá.
Ví dụ 2: Tận dụng được lợi ích từ “Đánh giá ngắn gọn”.
let obj = null;
if (obj && typeof obj === "object") {
console.log("Là Object");
} else
console.log("Không phải là Object"); // Kết quả được in ra
}
Cách viết này tối ưu hơn: Vì nếu obj là null, biểu thức sẽ ngay lập tức trả về null, và phần còn lại của biểu thức (typeof obj === "object") không cần được đánh giá. Điều này giúp tăng hiệu suất khi không cần phải thực hiện các đánh giá không cần thiết.
2.2 Kết luận: Cách tận dụng “Đánh giá ngắn gọn”
- Toán tử && (AND): Sắp xếp các điều kiện có khả năng trả về “falsy” nhiều hơn lên trước.
- Toán tử || (OR): Sắp xếp các điều kiện có khả năng trả về “truthy” nhiều hơn lên trước.
Điều này giúp tối ưu hóa việc đánh giá biểu thức và cải thiện hiệu suất của chương trình.
3. Các ứng dụng khác của toán tử AND và OR
Dựa vào nguyên lý hoạt động của toán tử && và || nên chúng có thể được sử dụng trong nhiều trường hợp khác nhau, không chỉ dùng với if-else.
3.1 Kiểm tra điều kiện và gọi hàm
Đề bài: Khi điều kiện đúng thì sẽ gọi một hàm.
Cách dùng if-else:
let greeting = "Xin chào!";
if (greeting) {
alert(greeting); // Xin chào!
}
Cách dùng toán tử AND:
let greeting = "Xin chào!";
greeting && alert(greeting); // Xin chào!
Trong trường hợp này, greeting có giá trị “truthy” ("Xin chào!"), do đó toán tử AND tiếp tục đánh giá và thực thi hàm alert(greeting).
3.2 Gán giá trị mặc định
Đề bài: Biến displayName chứa tên hiển thị được lấy từ userName, nếu không có userName thì giá trị mặc định là "Guest".
Cách dùng if-else:
let userName = null; // Có thể là null hoặc các chuỗi khác
let displayName = "Guest";
if (userName) {
displayName = userName;
}
console.log(displayName); // Guest
Cách dùng toán tử OR:
let userName = null; // Có thể là null hoặc các chuỗi khác
let displayName = userName || "Guest";
console.log(displayName); // Guest
Trường hợp này userName là null nên toán tử OR sẽ tiếp tục đánh giá tới giá trị "Guest” (truthy) và trả về giá trị này.
3.3 Lấy một giá trị theo độ ưu tiên
Đề bài: Cho 3 biến firstName, lastName và email phục vụ cho việc in ra tên người dùng. Luôn in ra một trong 3 giá trị, ưu tiên theo thứ tự firstName, lastName và email, nếu cả 3 biến không có giá trị thì không in ra.
Áp dụng toán tử OR và AND:
let firstName = "John";
let lastName = "Smith";
let email = "johnsmith@gmail.com";
let displayName = firstName || lastName || email;
displayName && console.log(displayName); // John
Nếu cả 3 biến không có giá trị, hiển thị tên mặc định là "Guest":
let firstName = null;
let lastName = null;
let email = null;
let displayName = firstName || lastName || email || "Guest";
console.log(displayName); // Guest
Cả toán tử AND và OR đều rất linh hoạt và có thể được sử dụng trong nhiều tình huống khác nhau, từ kiểm tra điều kiện đơn giản đến xây dựng logic phức tạp. Việc hiểu rõ cách sử dụng chúng sẽ giúp bạn viết code hiệu quả và dễ đọc hơn.
Tóm tắt
- Hoạt động của Toán tử AND (
&&): Trả về giá trị “falsy” đầu tiên hoặc giá trị cuối cùng nếu không có giá trị “falsy”. Thí dụ:false && truetrả vềfalse, còn6 && 8trả về8.- Ứng dụng trong kiểm tra điều kiện: Ví dụ, sử dụng
obj && typeof obj === "object"trong bài toán kiểm traobjkhông phảinullvà là một Object.
- Ứng dụng trong kiểm tra điều kiện: Ví dụ, sử dụng
- Hoạt động của Toán tử OR (
||): Trả về giá trị “truthy” đầu tiên hoặc giá trị cuối cùng nếu không có giá trị “truthy”. Thí dụ:1 || 0trả về1, còn"" || 0 || nulltrả vềnull.- Ứng dụng trong việc gán giá trị mặc định: Ví dụ,
let displayName = userName || "Guest".
- Ứng dụng trong việc gán giá trị mặc định: Ví dụ,
- Đánh giá ngắn gọn (Short-Circuit Evaluation): Toán tử
&&và||dừng đánh giá biểu thức khi đã đủ thông tin để quyết định kết quả, giúp tối ưu hiệu suất.- Ví dụ 1:
obj && typeof obj === "object"trả vềnullngay lập tức nếuobjlànull. - Ví dụ 2:
firstName || lastName || "Guest"trả vềfirstNamengay lập tức nếu có giá trị, nếu không thì trả vềlastName, hoặc"Guest".
- Ví dụ 1:
- Các ứng dụng khác: Toán tử
&&và||không chỉ dùng trongif-elsemà còn trong việc gọi hàm theo điều kiện, gán giá trị mặc định, và lựa chọn giá trị theo độ ưu tiên.