Học bằng cách đọc theo thứ tự

Rẽ nhánh điều kiện — else if, toán tử ba ngôi và switch

Học rẽ nhánh trong JavaScript từ nền tảng: else if để xét lần lượt từng bậc, toán tử ba ngôi trả về giá trị, và switch cùng vai trò của break.

Khi xác định hạng thành viên hay hiển thị trạng thái đơn hàng, điều kiện hiếm khi chỉ chia đôi gọn gàng. Nếu viết ba hạng Platinum, Gold và Regular bằng ba câu if riêng lẻ, các điều kiện bên dưới vẫn bị kiểm tra dù điều kiện phía trên đã cho ra kết quả, và số dòng in ra sẽ tùy vào số điều kiện đúng.

Bài này nói về else if để xét điều kiện theo từng bậc, toán tử ba ngôi trả về thẳng một giá trị, và switch để so một giá trị với nhiều ứng viên.

Chia thành ba trường hợp trở lên — nối tiếp else if

Giả sử bạn gán nhãn đánh giá dựa trên điểm trung bình của các review sản phẩm: từ 4.5 trở lên là "Rất tốt", từ 3.5 trở lên là "Tốt", thấp hơn nữa là "Chưa tốt".

Hai câu if đặt cạnh nhau được kiểm tra độc lập với nhau, nên với điểm 4.8 thì cả hai điều kiện đều đúng và màn hình in ra hai dòng: "Rất tốt" và "Tốt".

Khi nối tiếp bằng else if (điều kiện kế tiếp, chỉ được kiểm tra khi điều kiện trước đó sai), nhiều điều kiện gộp lại thành một cấu trúc rẽ nhánh duy nhất. Khối { } đi sau mỗi điều kiện được gọi là một nhánh.

Các điều kiện được kiểm tra từ trên xuống, và chỉ nhánh có điều kiện đúng đầu tiên được chạy. Nếu không điều kiện nào đúng, nhánh else sẽ chạy.

const score = 4.8;   // điểm review trung bình của sản phẩm

// Các câu if đặt cạnh nhau được kiểm tra độc lập
if (score >= 4.5) {
  console.log("Rất tốt");    // đúng
}
if (score >= 3.5) {
  console.log("Tốt");        // cũng đúng → in ra 2 dòng
}

// Nối bằng else if thì việc rẽ nhánh dừng ở nhánh đúng đầu tiên
if (score >= 4.5) {
  console.log("Rất tốt");    // chỉ nhánh này chạy
} else if (score >= 3.5) {
  console.log("Tốt");        // không được kiểm tra
} else {
  console.log("Chưa tốt");   // không được kiểm tra
}
Chuỗi else if được xét như thế nào
Bắt đầuscore = 4.8ifscore >= 4.5Rất tốtelse ifscore >= 3.5TốtelseChưa tốttruefalsetruefalsecòn lại

Điểm 4.8 thỏa score >= 4.5 ngay ở bậc đầu và đi sang phải, nên bậc thứ hai không được kiểm tra. Mũi tên chỉ đi xuống bậc tiếp theo khi điều kiện sai.

Bạn có thể bỏ else. Khi không có else và không điều kiện nào đúng, sẽ không nhánh nào chạy và chương trình đi tiếp xuống dòng nằm sau cả cấu trúc rẽ nhánh.

Bảng dưới đây cho thấy việc kiểm tra dừng ở bậc nào khi đưa ba mức điểm khác nhau qua cùng một chuỗi else if.

Điểm trung bìnhKiểm tra từ trên xuốngDòng được in ra
4.8Từ 4.5 trở lên là đúng, dừng tại đâyRất tốt (chỉ 1 dòng)
3.8Từ 4.5 trở lên là sai / từ 3.5 trở lên là đúngTốt (chỉ 1 dòng)
2.1Cả hai đều sai nên xuống nhánh elseChưa tốt (chỉ 1 dòng)

Thứ tự viết điều kiện làm thay đổi kết quả

Nếu đặt điều kiện bao phủ khoảng rộng lên trước, các điều kiện hẹp hơn bên dưới sẽ không bao giờ được xét tới. Nếu viết score >= 3.5 trước, sản phẩm được 4.8 điểm cũng bị chốt là "Tốt". Muốn 4.8 điểm là "Rất tốt", bạn đặt điều kiện hẹp hơn như score >= 4.5 lên trước.

Chuyển trạng thái của một đơn hàng thành dòng thông báo. orderId, isCanceled, isShipped và isPaid đã được khai báo sẵn.

① Hãy in ra một dòng theo dạng "Trạng thái đơn hàng A-1001".

② Hãy viết nhánh in ra "Đã hủy" nếu đơn hàng đã bị hủy.

③ Tiếp theo, hãy thêm các nhánh theo đúng thứ tự này: in "Đã giao cho vận chuyển" nếu đã gửi hàng, và "Đang chuẩn bị hàng" nếu đã thanh toán.

④ Nếu không rơi vào trường hợp nào ở trên, hãy in ra "Chờ thanh toán".

(Nếu chạy đúng, phần giải thích sẽ xuất hiện.)

JavaScript / TypeScript Editor

Chạy code để xem đầu ra

Nhận kết quả dưới dạng giá trị — cách viết toán tử ba ngôi

Có lúc bạn muốn chuyển qua lại giữa "Còn hàng" và "Hết hàng" theo số lượng tồn kho, rồi lưu chuỗi đó vào một biến để dùng lại. Nếu viết bằng ifelse thì không dùng được const, vì const phải nhận giá trị ngay lúc khai báo. Thay vào đó, bạn phải khai báo biến bằng let trước, rồi gán giá trị trong từng nhánh.

Những đoạn như stock > 0 — khi tính sẽ cho ra một giá trị — được gọi là biểu thức (expression). Còn những đoạn như if (…) { … } — chỉ thực hiện hành động mà không để lại giá trị nào — được gọi là câu lệnh (statement).

Với toán tử ba ngôi (ternary operator — biểu thức nhận ba phần là điều kiện, giá trị khi true và giá trị khi false, rồi trả về chính giá trị được chọn), bạn viết được cả hai nhánh trên một dòng.

const stock = 0;   // số lượng tồn kho

// if là câu lệnh nên khai báo và gán giá trị phải tách thành hai bước
let label;
if (stock > 0) {
  label = "Còn hàng";
} else {
  label = "Hết hàng";
}
console.log(label);   // Hết hàng

// Toán tử ba ngôi là biểu thức nên có thể gán thẳng vào const
const badge = stock > 0 ? "Còn hàng" : "Hết hàng";
console.log(badge);   // Hết hàng

// Cũng có thể viết thẳng bên trong template literal
console.log(`Trạng thái: ${stock > 0 ? "Có thể mua" : "Chờ nhập hàng"}`);  // Trạng thái: Chờ nhập hàng
Toán tử ba ngôi trở thành một giá trị như thế nào
stock > 0 ?"Còn hàng" :"Hết hàng"Điều kiện,giá trị khi true,giá trị khi falsestock là 00 > 0 là falseĐiều kiện đượctính trướcChọn "Hết hàng"bên phải dấu :Nếu true, chọn giátrị bên phải dấu ?const badge ="Hết hàng"Giá trị được chọnlà kết quả
Điều kiện 0 > 0 là false nên "Hết hàng" nằm bên phải dấu : được chọn. Cả biểu thức trở thành một giá trị duy nhất và được gán thẳng vào const.

Khi cần chia thành ba hướng trở lên, hãy quay về dùng else if. Toán tử ba ngôi có thể lồng vào nhau, nhưng khi đó ?: xuất hiện lặp đi lặp lại trên một dòng như a ? x : b ? y : z, và bạn phải dò bằng mắt xem điều kiện nào đi với giá trị nào.

In ra tiêu đề phần review và số điểm thưởng nhận được từ một lần mua hàng. reviewCount, isPremium và purchaseAmount đã được khai báo sẵn.

① Hãy in ra tiêu đề "Chưa có review nào" khi có 0 review, và "Số review: ◯" khi có từ 1 review trở lên.

② Hãy lưu tỷ lệ tích điểm vào một biến: 0.03 với thành viên Premium và 0.01 với những người còn lại.

③ Hãy nhân số tiền mua hàng với tỷ lệ ở ②, làm tròn xuống, rồi in ra "Điểm nhận được: ◯ pt (Thành viên thường)", với phần loại thành viên cũng thay đổi theo.

JavaScript / TypeScript Editor

Chạy code để xem đầu ra

Rẽ nhánh theo một giá trị — switch và case

Giả sử bạn cần hiển thị thông báo phí tùy theo phương thức thanh toán mà khách hàng đã chọn. Bạn có thể viết bằng else if, nhưng khi đó cùng một biến bị lặp lại nhiều lần — paymentMethod === "credit", paymentMethod === "convenience" — khiến người đọc khó nhận ra cấu trúc rẽ nhánh này đang so sánh cái gì.

Với switch (câu lệnh so một giá trị với nhiều ứng viên theo thứ tự, rồi bắt đầu chạy từ nhánh khớp), bạn chỉ viết giá trị cần so một lần trong cặp ngoặc tròn, rồi liệt kê các ứng viên dưới dạng case giá_trị:. break ở cuối mỗi nhánh sẽ thoát khỏi switch, và khi không có case nào khớp thì nhánh default: sẽ chạy.

const paymentMethod = "credit";   // phương thức thanh toán khách hàng đã chọn

switch (paymentMethod) {
  case "credit":
    console.log("Miễn phí");                  // nhánh này chạy
    break;
  case "convenience":
    console.log("Phí: 200 yên");              // thanh toán tại cửa hàng tiện lợi; không khớp
    break;
  case "cod":
    console.log("Phí: 330 yên");              // thanh toán khi nhận hàng; không khớp
    break;
  default:
    console.log("Hãy chọn cách thanh toán");
}
case khớp và nhánh default
Truyền vàocreditKhớp vớicase creditChạy nhánh đó,thoát bằng breakMiễn phíTruyền vàobankKhông khớp vớicase nào trong 3Chạy nhánhdefaultHãy chọn cáchthanh toán
credit khớp ngay ở case đầu tiên rồi thoát ra, còn bank không khớp với case nào trong ba case. Chỉ giá trị không khớp với case nào mới đi tới nhánh default.

Bạn có thể bỏ default. Khi switch không có default mà nhận một giá trị không khớp với case nào, sẽ không nhánh nào chạy và chương trình đi tiếp xuống dòng kế tiếp. Nếu có khả năng nhận giá trị nằm ngoài các ứng viên, hãy in một thông báo trong default để thấy ngay trên màn hình khi có giá trị ngoài dự kiến.

case phân biệt chuỗi và số khi so khớp

switch so khớp giống hệt ===, nên khác kiểu là không bao giờ khớp. Chuỗi "200" lấy từ ô nhập sẽ không khớp với case 200: mà đi vào default. Nếu một giá trị có thể là số hoặc chuỗi, hãy chuyển về cùng một kiểu trước khi so khớp.

Xác định phí vận chuyển dựa trên phương thức giao hàng. shippingMethod, itemTotal và shippingFee đã được khai báo sẵn.

① Hãy dùng switch để đặt phí vận chuyển là 500 với standard và 900 với express.

② Hãy thêm nhánh đặt phí là 0 với store (nhận hàng tại cửa hàng).

③ Nếu không rơi vào trường hợp nào ở trên, hãy in ra "Vui lòng kiểm tra phương thức giao hàng".

④ Sau switch, hãy in ra "Phí vận chuyển: ◯ yên / Tổng: ◯ yên".

JavaScript / TypeScript Editor

Chạy code để xem đầu ra

Chạy tràn xuống case tiếp theo — khi bỏ break

Một chỗ dễ vấp khi dùng switch là quên viết break. Code vẫn đúng cú pháp nên không có lỗi cú pháp nào; bạn chỉ nhận ra khi chạy và thấy màn hình in ra nhiều hơn một dòng.

Khi xảy ra fall-through (vì thiếu break nên code của các case nằm dưới case khớp cũng được chạy tiếp), chương trình cứ thế chạy tiếp — không so sánh với giá trị ghi ở các case bên dưới — cho tới khi gặp break hoặc tới cuối switch.

const orderStatus = "paid";   // trạng thái đơn hàng

// Không có break thì code bên dưới case khớp cũng chạy tiếp
switch (orderStatus) {
  case "paid":
    console.log("Đã thanh toán");                 // khớp, bắt đầu từ đây
  case "shipped":
    console.log("Đã giao cho vận chuyển");        // không có break nên chạy tiếp
  default:
    console.log("Vui lòng kiểm tra trạng thái");  // chạy tới tận default
}

// Xếp các case liền nhau để nhiều ứng viên dùng chung một khối code
switch (orderStatus) {
  case "pending":
  case "paid":
    console.log("Chưa gửi hàng");   // cả pending lẫn paid đều vào đây
    break;
}
Có break và không có break
Trạng thái: paidKhớp vớicase paidbreak thoátkhỏi switchIn ra 1 dòngTrạng thái: paidKhớp vớicase paidCác case bên dướicũng chạy tiếpIn ra 3 dòng
Cùng là trạng thái paid, nhưng nếu bỏ break thì màn hình in ra thêm "Đã giao cho vận chuyển" và "Vui lòng kiểm tra trạng thái". Có hay không có break sẽ làm thay đổi số dòng được in ra.

Bạn có thể tận dụng cách hoạt động này khi muốn nhiều ứng viên dùng chung một khối code. Nếu xếp hai nhãn case liền nhau mà không viết code ở giữa, khi khớp với case phía trên, chương trình sẽ đi thẳng xuống code bên dưới. Hãy đặt break ở cuối nhánh dùng chung đó.

In ra các tính năng dùng được của từng gói dịch vụ. Biến plan chứa gói đang dùng đã được khai báo sẵn.

① Hãy in ra tiêu đề theo dạng "Tính năng của gói standard".

② Hãy viết một switch và in ra "Xem offline" trong nhánh premium.

③ Bên dưới, hãy thêm nhánh standard in ra "Chất lượng HD" và nhánh free in ra "Xem video", không viết break.

④ Hãy thêm một case để trial chạy cùng khối code với free.

JavaScript / TypeScript Editor

Chạy code để xem đầu ra
QUIZ

Kiểm tra kiến thức

Hãy trả lời từng câu hỏi một.

Câu 1Trong một chuỗi else if đặt >= 50000 trước và >= 100000 sau, khi truyền vào 120000 thì nhánh nào chạy?

Câu 2total >= 5000 ? 0 : 500 trả về gì khi total là 5000?

Câu 3Nếu quên viết break ở cuối một case thì chuyện gì xảy ra?