Δομές ελέγχου ροής: switch statement
Στο προηγούμενο κεφάλαιο, μάθαμε για το if...else
statement και πώς μπορούμε να εκτελέσουμε κώδικα βάσει μιας συνθήκης. Και ενώ το if...else
statement καλύπτει όλες μας τις ανάγκες όσον αφορά την υπό συνθήκη εκτέλεση ενός block κώδικα, το switch
statement μπορεί να μας βοηθήσει να επιτύχουμε παρόμοια αποτελέσματα, προσφέροντας μια πιο “καθαρή” και ευανάγνωστη λύση.
Σε αυτό το κεφάλαιο, λοιπόν, θα μιλήσουμε για το switch
statement, τα βασικά χαρακτηριστικά και τη χρησιμότητά του, καθώς και τις διαφορές του με το if...else
statement.
Το switch
statement
Το switch
statement είναι ένας τρόπος να ελέγχουμε τη ροή του προγράμματός μας, επιλέγοντας διαφορετικά “μονοπάτια” εκτέλεσης με βάση την τιμή μιας συγκεκριμένης έκφρασης (συνήθως μιας μεταβλητής).
Σκεφτείτε το σαν τον πίνακα με τα πλήκτρα σε έναν ανελκυστήρα. Όταν πιέσουμε κάποιο πλήκτρο από τον πίνακε–η τιμή του expression μας–ο ανελκυστήρας “διαβάζει” τον όροφο και μας μεταφέρει σε αυτό–εκτελείται το αντίστοιχο block κώδικα. Αν για κάποιο λόγο δεν πατήσουμε κάποιο πλήκτρο ή υπάρχει βλάβη, τότε ο ανεκλυστήρας θα κάνει αυτό που είναι προγραμματισμένος να κάνει σε αυτές τις περιπτώσεις (default behaviour): θα κλείσει τις πόρτες και θα παραμείνει ακίνητος. Στο παράδειγμα αυτό η τιμή που μας ενδιαφέρει είναι το σήμα που θα μεταφέρει το πλήκτρο στον πίνακα και η διεργασία που θα εκτελεστεί είναι η μετακίνηση του ανεκλυστήρα.
Συγκρίνοντας αυτή τη προσέγγιση με τον τρόπο που λειτουργεί το if
statement, βλέπουμε ότι δεν έχουμε να κάνουμε μόνο με την ικανοποίηση κάποιας συνθήκης (πχ., αν θα πατήσω κάποιο πλήκτρο), αλλά και με την ίδια την τιμή. Αυτή είναι και η βασική διαφορά μεταξύ των δύο conditional statements.
Σύνταξη switch
Ένας ακόμα λόγος που χρησιμοποιούμε το switch
statement είναι η βελτίωση της αναγνωσιμότητας του κώδικα. Όταν έχουμε πολλά if...else if
statements που ελέγχουν την ίδια μεταβλητή για διαφορετικές τιμές, ο κώδικας μπορεί να γίνει μακροσκελής και δύσκολος στην ανάγνωση. To switch
μας βοηθά να οργανώσουμε αυτά τα σενάρια με πιο δομημένο τρόπο.
Ένα switch
statement συντάσσεται ως εξής:
switch (expression) {
case τιμή_1:
// Κώδικας αν expression === τιμή_1
break;
case τιμή_2:
// Κώδικας αν expression === τιμή_2
break;
case τιμή_N:
// Κώδικας για την Ν-οστή περίπτωση
break;
default:
// Κώδικας αν καμία περίπτωση δεν ταιριάζει
break;
}
Παράδειγμα
Για να κατανοήσουμε καλύτερα πώς συντάσσεται ένα switch
statement και γιατί ενδεχομένως ένα switch
να είναι προτιμότερο από ένα if
statement, ας δούμε το παρακάτω σενάριο. Ας υποθέσουμε ότι θέλουμε να τυπώσουμε ένα μήνυμα σχετικά με το αν κάποια ημέρα της εβδομάδας είναι εργάσιμη ή όχι. Με ενα if
statement αυτό θα μπορούσε να γίνει ως εξής:
1const ημέρα = "Δευτέρα";
2
3if (ημέρα === "Δευτέρα") {
4 console.log("εργάσιμη");
5} else if (ημέρα === "Τρίτη") {
6 console.log("εργάσιμη");
7} else if (ημέρα === "Τετάρτη") {
8 console.log("εργάσιμη");
9} else if (ημέρα === "Πέμπτη") {
10 console.log("εργάσιμη");
11} else if (ημέρα === "Παρασκευή") {
12 console.log("εργάσιμη");
13} else if (ημέρα === "Σαββάτο") {
14 console.log("σαββατοκύριακο");
15} else if (ημέρα === "Κυριακή") {
16 console.log("σαββατοκύριακο");
17} else {
18 console.log("λάθος τιμή");
19}
Το παραπάνω κομμάτι κώδικα δουλεύει άψογα και θα καλύψει όλες μας τις ανάγκες, αλλά τα επαναλαμβανόμενα expressions που χρησιμοποιούμε σαν συνθήκες κάνουν τον κώδικά μας αρκετά “φορτωμένο” στο μάτι. Ας δούμε πως μπορούμε να λύσουμε αυτό το πρόβλημα με ένα switch
statement, ακολουθώντας τον τρόπο σύνταξης που είδαμε παραπάνω:
1const ημέρα = "Δευτέρα";
2
3switch (ημέρα) {
4 case "Δευτέρα":
5 console.log("εργάσιμη");
6 break;
7
8 case "Τρίτη":
9 console.log("εργάσιμη");
10 break;
11
12 case "Τετάρτη":
13 console.log("εργάσιμη");
14 break;
15
16 case "Πέμπτη":
17 console.log("εργάσιμη");
18 break;
19
20 case "Παρασκευή":
21 console.log("εργάσιμη");
22 break;
23
24 case "Σαββάτο":
25 console.log("σαββατοκύριακο");
26 break;
27
28 case "Κυριακή":
29 console.log("σαββατοκύριακο");
30 break;
31
32 default:
33 console.log("λάθος τιμή");
34}
Ας δούμε αναλυτικά τι συμβαίνει σε κάθε μέρος:
Αρχικά, ορίζουμε το block statement το οποιο θα ελέγχει την τιμή του expression πάνω στην οποία θα βασίσουμε το σενάριο μας–ουσιαστικά δημιουργούμε το switch
statement ή το switch
block:
1const ημέρα = "Δευτέρα";
2
3switch (ημέρα) {
4 case "Δευτέρα":
5 console.log("εργάσιμη");
6 break;
7
8 // ...
9}
Στην συνέχεια ορίζουμε τις περιπτώσεις που θέλουμε να καλύψουμε για κάθε τιμή κάνοντας χρήση της λέξης-κλειδί case
. Αν η τιμή που επιστρέφει το expression ταιριάζει με την τιμή του case
, τότε ο κώδικας που αντιστοιχεί σε αυτό το case
block θα εκτελεστεί:
1const ημέρα = "Δευτέρα";
2
3switch (ημέρα) {
4 case "Δευτέρα":
5 console.log("εργάσιμη");
6 break;
7
8 // ...
9}
Παρατηρούμε ότι στο τέλος κάθε του case
block υπάρχει η λέξη κλειδί break
:
1const ημέρα = "Δευτέρα";
2
3switch (ημέρα) {
4 case "Δευτέρα":
5 console.log("εργάσιμη");
6 break;
7
8 // ...
9}
Τέλος, βλέπουμε ότι το τελευταίο block κώδικα αντιστοιχεί στο default
statement, το οποίο αν και προαιρετικό, θεωρείται καλή πρακτική να περιλαμβάνουμε ένα default
statement. Το default
statement λειτουργεί ακριβώς όπως το else
σε ένα if
statement: αν κανένα από τα case
statements δεν εκτελεστεί, τότε θα εκτελεστεί ο κώδικας default
block.
1const ημέρα = "Δευτέρα";
2
3switch (ημέρα) {
4 case "Δευτέρα":
5 console.log("εργάσιμη");
6 break;
7
8 // ...
9
10 default:
11 console.log("λάθος τιμή");
12}
Με μια πρώτη ματιά ο κωδικάς μας σχεδόν διπλασιάστηκε σε έκταση (σσ: γραμμές)! Αυτό όμως δεν είναι απαραίτητα κακό αν εξυπηρετείται ο αρχικός μας σκοπός μας: να οργανώσουμε και να κάνουμε τον κώδικά μας πιο απλό και ευανάγνωστο. Μετατρέποντας ένα if
statement σε switch
ξέρουμε ότι υπάρχει ένα μοναδικό expression που πρέπει να ελέγξουμε και τα σενάριά μας εξαρτόνται από την τιμή που επιστρέφει το expression κατά το evaluation. Εξ ορισμού, κάτι τέτοιο είναι πολύ πιο απλό από ένα if...else
statement.
Η συμπεριφορά Fall-Through
Όπως αναφέραμε, αν ξεχάσουμε να συμπεριλάβουμε το break
statement σε κάποιο case
block, η εκτέλεση θα συνεχιστεί στο επόμενο case
statement και μέχρι να συναντήσει κάποιο break
statement ή το τέλος το switch
block. Αυτή η συμπεριφορά ονομάζεται Fall-Through. Συνήθως, είναι μια συμπεριφορά που θέλουμε να αποφύγουμε, αλλά υπάρχουν περιπτώσεις όπου μπορεί να είναι χρήσιμο, ειδικά όταν θέλουμε να εκτελέσουμε τον ίδιο κώδικα για πολλαπλές τιμές.
Στο προηγούμενο μας παράδειγμα, τα case
blocks για τις τιμές "Δευτέρα"
, "Τρίτη"
, "Τετάρτη"
, "Πέμπτη"
και "Παρασκευή"
ήταν τα ίδια, καθώς και για τις τιμές "Σαββάτο"
και "Κυριακή"
. Εκμεταλλευόμενοι την συμπεριφορά Fall-Through, θα μπορούσαμε να αφαιρέσουμε τα break;
statements και να συμπτύξουμε τα case
statements για αυτές τις τιμές σε ένα:
1const ημέρα = "Τρίτη";
2
3switch (ημέρα) {
4 case "Δευτέρα":
5 case "Τρίτη":
6 case "Τετάρτη":
7 case "Πέμπτη":
8 case "Παρασκευή":
9 console.log("εργάσιμη");
10 break;
11
12 case "Σάββατο":
13 case "Κυριακή":
14 console.log("σαββατοκύριακο");
15 break;
16
17 default:
18 console.log("λάθος τιμή");
19}
Εδώ, αν η ημέρα είναι "Τρίτη"
, δεν υπάρχει break;
μετά το case "Δευτέρα"
, οπότε η εκτέλεση “πέφτει” στο case "Τρίτη"
και συνεχίζει. Όλα τα σενάρια για τις καθημερινές ημέρες οδηγούν στο να τυπωθεί το ίδιο μήνυμα "εργάσιμη"
πριν το break
τερματίσει την εκτέλεση του switch
statements
Θα μπορούσαμε να επιτύχουμε το ίδιο αποτέλεσμα με if..else if
statements, αλλά ο κώδικάς μας θα γινόταν αρκετά πιο πολύπλοκος καθώς θα έπρεπε να διαχειριστούμε πολλαπλά expressions για μία μόνο τιμή:
1const ημέρα = "Τρίτη";
2
3if (
4 ημέρα === "Δευτέρα" ||
5 ημέρα === "Τρίτη" ||
6 ημέρα === "Τετάρτη" ||
7 ημέρα === "Πέμπτη" ||
8 ημέρα === "Παρασκευή"
9) {
10 console.log("εργάσιμη");
11} else if (ημέρα === "Σάββατο" || ημέρα === "Κυριακή") {
12 console.log("σαββατοκύριακο");
13} else {
14 console.log("λάθος τιμή");
15}
Τί να προσέξεις
Στα παραδείγματά μας μέχρι τώρα, παρατηρήσαμε ότι το default
block δεν τερμάτιζε με break
statement. Αυτό συνέβη επειδή βρισκόταν στο τέλος των case
blocks, ακριβώς πριν ολοκληρωθεί το switch
statement. Ωστόσο, αν είχαμε τοποθετήσει το default
block ανάμεσα σε άλλα case
blocks χωρίς να το τερματίσουμε με ένα break
statement, τότε η fall-through συμπεριφορά θα εφαρμοζόταν και σε αυτό, όπως ακριβώς και στα υπόλοιπα μπλοκ που έχουμε δει.
Ας δούμε το ακόλουθο παράδειγμα:
1const θερμοκρασία = 35;
2
3switch (θερμοκρασία) {
4 case 10:
5 console.log("Κάνει κρύο");
6
7 default:
8 console.log("Φυσιολογικός καιρός");
9
10 case 25:
11 console.log("Κάνει ζέστη");
12
13 case 40:
14 console.log("Καύσωνας");
15}
Τα μηνύματα που θα εκτυπώσει είναι στην κονσόλα μας είναι:
"Φυσιολογικός καιρός"
"Κάνει ζέστη"
"Καύσωνας"
Και αυτό γιατί, με το που συνάντησε την πρώτη περίπτωση που ικανοποίησε την τιμή της μεταβλητής–στη συγκεκριμένη περίπτωση, το default
statement–η εκτέλεση δεν τερματίστηκε ποτέ, καθώς δεν υπήρχε κάποιο break
statement για να την σταματήσει. Ως εκ τούτου, η σειρά με την οποία δηλώνονται τα case
και default
statements παίζει πολύ σημαντικό ρόλο όταν εφαρμόζεται η συμπεριφορά fall-through.
Διαφορές switch
και if
statement
Χαρακτηριστικό | switch statement | if...else if statement |
---|---|---|
Βασικός σκοπός | Εκτέλεση διαφορετικού κώδικα με βάση πολλές πιθανές τιμές μιας και μόνο έκφρασης. | Εκτέλεση διαφορετικού κώδικα με βάση μία ή περισσότερες συνθήκες. |
Σύγκριση | Χρησιμοποιεί αυστηρή ισότητα (=== ) για σύγκριση της έκφρασης με τις τιμές των case statement. | Επιτρέπει χρήση λογικών ή συγκριτικών τελεστών (π.χ., == , === , < , > , && , || ). |
Ευανάγνωστη για | Πολλές πιθανές τιμές μιας και μόνο έκφρασης. | Σύνθετες συνθήκες, έλεγχοι εύρους, ή όταν οι συνθήκες αφορούν διαφορετικές μεταβλητές. |
Αποφυγή fall-through | Απαιτεί break για την έξοδο από το switch μπλοκ. Αν παραλειφθεί, συμβαίνει “fall-through” στο επόμενο case statement. | Δεν υπάρχει αντίστοιχο “fall-through” πρόβλημα. Κάθε if ή else if statement αξιολογείται ξεχωριστά. |
Προεπιλεγμένη λογική | Χρησιμοποιεί το default block αν δεν ταιριάζει κανένα case statement . | Χρησιμοποιεί το else block αν καμία if ή else if συνθήκη δεν είναι αληθής. |
Περιορισμοί | Οι τιμές των case statements πρέπει να είναι τιμές. Δεν μπορούν να περιέχουν λογική. | Οι συνθήκες μπορούν να είναι οποιαδήποτε έγκυρη λογική έκφραση. |