Μεταβλητές και σταθερές

Σε αυτή την ενότητα θα μιλήσουμε για τις μεταβλητές στον προγραμματισμό και θα δούμε ποιες είναι οι ιδιότητες και τα χαρακτηριστικά τους στην JavaScript.

Το επεισόδιο στο YouTube

Εισαγωγή

Στην προηγούμενη ενότητα αναφερθήκαμε στην έννοια της τιμής στον προγραμματισμό, καθώς και στους πρωτογενείς τύπους δεδομένων (primitive data types) που υποστηρίζονται από την JavaScript και που μπορεί να λάβει μια τιμή.

Επιγραμματικά, οι υποστηριζόμενοι τύποι δεδομένων στην JavaScript είναι οι εξής:

ΤύποςΧρησιμοποιείται γιαΑναπαράσταση
Numberακέραιους αριθμούς (integers) και αριθμούς κινητής υποδιαστολής (floats)1 3.13 -20
Stringακολουθίες χαρακτήρων (συμβολοσειρές) που περικλείονται σε μονά ' ή διπλά " εισαγωγικά ή backticks `"Jason" 'hello world' `javascript`
Booleanαληθής και ψευδής τιμέςtrue false
Nullκενή τιμήnull
Undefinedμή ύπαρξη τιμής ή μή ορισμένη τιμήundefined
BigIntακέραιους αριθμούς που ξεπερνούν την μέγιστη τιμή που μπορεί να υποστηρίξει ο τύπος NumberBigInt("90071992547409910") 90071992547409910n
Symbolμοναδικά και αμετάβλητα identifiers που χρησιμοποιούνται ως κλειδιά αντικειμένων (object properties)Symbol("foo")

Ποιος ο ρόλος των μεταβλητών;

Στην προηγούμενη ενότητα της σειράς Προγραμματισμός από το Μηδέν, είδαμε πώς μπορούμε να ορίσουμε τιμές στην κονσόλα (console) των DevTools του Chrome.

Οι τιμές αυτές ήταν εφήμερες τιμές (ephemeral values), με την έννοια ότι, από την στιγμή που έγιναν evaluate και μας επεστράφησαν ως output, έπαψαν να είναι διαθέσιμες για μετέπειτα χρήση στην κονσόλα· «έζησαν» προσωρινά στην μνήμη του υπολογιστή και για όσο χρονικό διάστημα είχαμε ανοιχτά τα Devtools. Αυτό σημαίνει πως αν χρειαζόμασταν να ανατρέξουμε σε μια συγκεκριμένη τιμή, τότε θα έπρεπε να την εισάγουμε σε κάθε σημείο και για όσες φορές θα μας ήταν απαραίτητη.

Όπως γίνεται αντιληπτό, στον κόσμο των υπολογιστών, όπου καλούμαστε να διαχειριστούμε έναν τεράστιο όγκο δεδομένων, αποτέλεσμα πολύπλοκων διεργασιών, κάτι τέτοιο δεν είναι πολύ χρήσιμο ή ευέλικτο. Ευτυχώς για εμάς οι γλώσσες προγραμματισμού παρέχουν τα κατάλληλα εργαλεία για να κάνουν την ζωή μας αρκετά πιο εύκολη. Τα εργαλεία αυτά ονομάζονται μεταβλητές.

Μεταξύ άλλων, οι μεταβλητές είναι απαραίτητες στον προγραμματισμό για:

  • την αποθήκευση και τη διαχείριση δεδομένων κατά την εκτέλεση ενός προγράμματος,
  • τον έλεγχο της ροής της εκτέλεσης προγραμμάτων, και
  • τη συγγραφή κώδικα που είναι εύκολος στην παραμετροποίηση.

Στις περισσότερες γλώσσες προγραμματισμού, οι μεταβλητές δεν είναι τίποτα παραπάνω από διευθύνσεις—συμβολικά ονόματα (ελ) ή identifiers (en)—που αντιστοιχούν σε θέσεις μνήμης στον υπολογιστή. Κατά τον ορισμό τους, η μνήμη δεσμεύεται με βάση τον τύπο δεδομένων που θα αποθηκεύσουν. Οι τιμές που ανατίθενται στις μεταβλητές αντικαθιστούν τυχόν υπάρχοντα δεδομένα στην ίδια θέση μνήμης.

Κατά την εκτέλεση ενός προγράμματος, οι μεταβλητές μας επιτρέπουν να ανακτούμε και να τροποποιούμε με ευκολία τα δεδομένα που είναι αποθηκευμένα στις θέσεις μνήμης που έχουμε δεσμεύσει. Το εύρος (scope) και η διάρκεια ζωής (lifetime) μιας μεταβλητής καθορίζουν το πού και πότε τα δεδομένα αυτά θα είναι προσβάσιμα.

Τα χαρακτηριστικά των μεταβλητών διαφέρουν από γλώσσα σε γλώσσα προγραμματισμού. Η βασικές αρχές του τρόπου λειτουργίας τους, όμως, είναι η ίδια ανεξάρτητα από την γλώσσα προγραμματισμού, το λειτουργικό ή την πλατφόρμα στην οποία εκτελείται ένα πρόγραμμα.

Ακολουθεί ένα παράδειγμα για να γίνουν όλα όσα περιγράψαμε πιο εύκολα αντιληπτά.

Το παράδειγμα της βιβλιοθήκης

Ας υποθέσουμε ότι χρειαζόμαστε ένα βιβλίο από τη δανειστική βιβλιοθήκη της περιοχής μας και για αυτό το λόγο αποφασίζουμε να την επισκεφτούμε. Πάει καιρός από την τελευταία μας επίσκεψη και έτσι δεν θυμόμαστε πως είναι οργανωμένοι οι διαθέσιμοι τίτλοι βιβλίων, ούτε το πού ακριβώς βρίσκεται το βιβλίο που ψάχνουμε. Γνωρίζουμε όμως με σιγουριά πως το βιβλίο που μας ενδιαφέρει υπάρχει κάπου μέσα στην βιβλιοθήκη.

Από την στιγμή που δεν μπορούμε να ανασύρουμε από την μνήμη μας την πληροφορία για το ράφι στο οποίο βρίσκεται το βιβλίο, θα μπορούσαμε να πούμε πως η γνώση μας για την θέση του είναι εφήμερη, όπως ακριβώς και οι τιμές που εισάγαμε στην κονσόλα των DevTools.

Δίχως να χάσουμε χρόνο απευθυνόμαστε στον βιβλιοθηκονόμο, ο οποίος μετά από αναζήτηση στους καταλόγους της βιβλιοθήκης μας κατευθύνει στο σημείο —διάδρομο και ράφι— που βρίσκεται το βιβλίο που μας ενδιαφέρει. Παράλληλα, για να αποφύγουμε άσκοπες μελλοντικές αναζητήσεις για το συγκεκριμένο βιβλίο, σημειώνουμε τις πληροφορίες για την θέση του βιβλίου στο σημειωματάριο μας.

Με το να γράψουμε αυτό το σημείωμα ορίσαμε μια μεταβλητή—έστω και άθελά μας! Η μεταβλητή μας (σημείωμα) αντιστοιχεί στη μια θέση μνήμης (διάδρομος και ράφι) που έχει δεσμευτεί στην μνήμη (βιβλιοθήκη) ώστε να αποθηκεύσει μια τιμή (βιβλίο).

Με απλά λόγια, οι μεταβλητές είναι σαν τις εγγραφές σε κάποιο ευρετήριο. Μπορούμε να ορίζουμε, να διαγράφουμε ή να αλλάζουμε την τιμή μιας μεταβλητής, όπως ακριβώς μπορούμε να προσθέτουμε, να αφαιρούμε ή να ενημερώνουμε εγγραφές για την τοποθεσία των βιβλίων από το σημειωματάριο μας.

Μεταβλητές στην JavaScript

Σε αυτή την ενότητα θα δούμε μερικές απο τις ιδιότητες των μεταβλητών στην JavaScript.

Ορισμός μεταβλητών

Αρχικώς, για να υπάρξει μια μεταβλητή πρέπει να γίνει ο ορισμός της (variable definition). Στην JavaScript αυτό γίνεται με την χρήση των keywords var, let ή const, ακολουθούμενα από το συμβολικό όνομα (identifier), τον τελεστή ανάθεσης = (assignment operator) και την τιμή (value) που θέλουμε να της δώσουμε.

Για παράδειγμα:

const name = "Jason";
let year = 2024;
var rain = false;

Ο ενδεδειγμένος τρόπος ορισμού μεταβλητών είναι κάνοντας χρήση των keywords let και const. Ιστορικά, ο ορισμός μεταβλητών στην JavaScript πραγματοποιούνταν με το keyword var, κάτι που πλέον θεωρείται ξεπερασμένο. Ο λόγος για αυτό είναι ότι υστερεί σε σχέση με τα keywords let και const σε ό,τι αφορά το εύρος ορισμού της μεταβλητής (variable scope), μια εννοια που θα δούμε σε επόμενη ενότητα.

Κανόνες ονοματοθεσίας μεταβλητών

Τα συμβολικά ονόματα (identifiers) που μπορούν να έχουν οι μεταβλητές υπόκεινται σε κάποιους πολύ απλούς κανόνες. Πιο συγκεκριμένα:

  • δεν μπορούν να είναι δεσμευμένες λέξεις-κλειδιά (reserved words)
  • δεν μπορούν να ξεκινούν με αριθμό
  • δεν μπορούν να περιέχουν κενά
  • δεν μπορούν να περιέχουν ειδικούς χαρακτήρες με εξαίρεση:
    • την κάτω παύλα _ (underscore) και
    • το σήμα του δολαρίου $

Για παράδειγμα, όλα τα παρακάτω μπορούν να χρησιμοποιηθούν ως ονόματα μεταβλητών:

let name;
let _day;
let day2;
let $btc;

Αντιθέτως, όλα τα παρακάτω θα προκαλέσουν σφάλμα κατά την εκτέλεση:

let n me; // Uncaught SyntaxError: Unexpected identifier 'me'
let if;   // Uncaught SyntaxError: Unexpected token 'if'
let 2day; // Uncaught SyntaxError: Unexpected token
let @btc; // Uncaught SyntaxError: Unexpected token

Στην JavaScript τα ονόματα των μεταβλητών είναι case-sensitive, δηλαδή υπάρχει διαφοροποίηση μεταξύ μεταβλητών που έχουν το ίδιο όνομα αλλά διαφορετικό τρόπο γραφής σε ό,τι αφορά τους κεφαλαίους και πεζούς χαρακτήρες.

Για παράδειγμα, οι παρακάτω μεταβλητές είναι διαφορετικές:

const name = "Jason";
const Name = "Coder";

console.log(name === Name); // false

Όπως θα δούμε σε επόμενη ενότητα, οι ίδιοι κανόνες ονοματοθεσίας εφαρμόζονται και στα ονόματα των συναρτήσεων (functions).

Κάλεσμα μεταβλητών

Με τον όρο κάλεσμα μεταβλητής (to call a variable) εννοούμε την διεργασία κατά την οποία κάνουμε χρήση του identifier μιας μεταβλητής ώστε να ανακτήσουμε την τιμή που είναι δεσμευμένη στην μνήμη του υπολογιστή για αυτή.

Στην JavaScript και σε πολλές άλλες γλώσσες προγραμματισμού αυτό γίνεται με το να δώσουμε ως input ή να συμπεριλάβουμε σε ένα statement το identifier την μεταβλητής που μας ενδιαφέρει.

Για παράδειγμα:

const name = "Jason";

console.log(name); // to call variable "name"

Για καλέσουμε μια μεταβλητή πρέπει πρώτα να την έχουμε ορίσει, διαφορετικά θα προκύψει σφάλμα.

Για παράδειγμα:

console.log(name); // Uncaught ReferenceError: name is not defined

Ανάθεση τιμής σε μεταβλητές

H JavaScript ανήκει στις λεγόμενες δυναμικές γλώσσες προγραμματισμού (dynamically typed languages). Αυτό σημαίνει ότι μπορεί να γίνει ανάθεση τιμών οποιουδήποτε τύπου δεδομένων τόσο κατά τον ορισμό μεταβλητών όσο και κατά την διάρκεια εκτέλεσης ενός προγράμματος (runtime).

Για παράδειγμα:

// ανάθεση τιμής κατά τον ορισμό
let year = 2024;
var rain = false;

// ανάθεση τιμής κατά την εκτέλεση
year = "foo bar";
rain = true;

Ένα χαρακτηριστικό της JavaScript είναι ότι επιτρέπει τον ορισμό μεταβλητών χωρίς αναθεση τιμής. Σε αυτή την περίπτωση οι μεταβλητές αυτές λαμβάνουν αυτόματα την τιμή undefined, τύπου Undefined, κάτι που είδαμε και στην προηγούμενη ενότητα.

Για παράδειγμα:

let year;

console.log(year); // undefined

Διαφορά let και const

Η βασική διαφορά μεταξύ των μεταβλητών που ορίζονται από τα keywords let και const είναι ότι στις μεταβλητές που έχουν οριστεί με το keyword let επιτρέπεται η ανάθεση τιμής κατά την διάρκεια εκτέλεσης του προγράμματος:

let year = 2024;
year = "foo bar";

Επίσης, επιτρέπεται ο ορισμός μιας μεταβλητής χωρίς αρχική ανάθεση τιμής:

let rain;

Αυτό δεν ισχύει για τις μεταβλητές που ορίζονται από το keyword const και αν επιχειρήσουμε κάποιες από τις παραπάνω διεργασίες θα προκύψει σφάλμα κατά την εκτέλεση και το πρόγραμμα θα τερματιστεί.

Για παράδειγμα:

const name = "Jason";
name = "true"; // Uncaught TypeError: Assignment to
               // constant variable.

const demo; // Uncaught SyntaxError: Missing initializer
            // in const declaration