Εξηγήστε πώς λειτουργεί η κληρονομικότητα στη JavaScript.
sobes.tech AI
Απάντηση από AI
Η κληρονομιά στο JavaScript υλοποιείται μέσω πρωτοτύπων. Κάθε αντικείμενο στο JavaScript έχει μια εσωτερική ιδιότητα [[Prototype]], η οποία αναφέρεται σε ένα άλλο αντικείμενο. Όταν προσπαθούμε να αποκτήσουμε πρόσβαση σε μια ιδιότητα ή μέθοδο ενός αντικειμένου που δεν υπάρχει άμεσα σε αυτό, ο μηχανισμός JavaScript αναζητά αυτήν την ιδιότητα ή μέθοδο στο πρωτότυπο αυτού του αντικειμένου. Αν δεν το βρει εκεί, συνεχίζει την αναζήτηση κατά μήκος της αλυσίδας πρωτοτύπων που σχηματίζεται από τις συνδέσεις [[Prototype]], μέχρι να φτάσει στο null (το τέλος της αλυσίδας).
Υπάρχουν δύο βασικοί μηχανισμοί κληρονομιάς:
-
Κλασική πρωτοτυπική κληρονομιά (ES5 και παλαιότερα): Βασίζεται στη χρήση συναρτήσεων-κατασκευαστών και της ιδιότητας
prototypeτους.// Συνάρτηση-κατασκευαστής function Ζώο(όνομα) { this.όνομα = όνομα; } // Προσθέτουμε μέθοδο στο πρωτότυπο Ζώο.prototype.μιλάει = function() { console.log(`${this.όνομα} κάνει ήχο.`); }; // Δημιουργία στιγμιότυπου const σκύλος = new Ζώο('Σκύλος'); // Κλήση μεθόδου από το πρωτότυπο σκύλος.μιλάει(); // Έξοδος: Σκύλος κάνει ήχο. // Το πρωτότυπο του σκύλου είναι το `Ζώο.prototype` console.log(Object.getPrototypeOf(σκύλος) === Ζώο.prototype); // true -
Κλάση (ES6 και μετά): Χρησιμοποιεί τη σύνταξη
classκαιextends, που κάτω από την κουκούλα δουλεύει με πρωτότυπα.// Βασική κλάση class Ζώο { constructor(όνομα) { this.όνομα = όνομα; } μιλάει() { console.log(`${this.όνομα} κάνει ήχο.`); } } // Υποκλάση που κληρονομεί από το Ζώο class Σκύλος extends Ζώο { constructor(όνομα, φυλές) { super(όνομα); // Κλήση του κατασκευαστή της γονικής κλάσης this.φυλές = φυλές; } γαβγίζει() { console.log(`${this.όνομα} γαβγίζει.`); } } // Δημιουργία στιγμιότυπου υποκλάσης const οδυσσέας = new Σκύλος('Bublik', ['Labrador', 'Collie']); // Κλήση μεθόδων τόσο από το Ζώο όσο και από το Σκύλος οδυσσέας.μιλάει(); // Έξοδος: Bublik κάνει ήχο. οδυσσέας.γαβγίζει(); // Έξοδος: Bublik γαβγίζει. // Το πρωτότυπο του οδυσσέα είναι το `Σκύλος.prototype` console.log(Object.getPrototypeOf(οδυσσέας) === Σκύλος.prototype); // true // Το πρωτότυπο του `Σκύλος.prototype` είναι το `Ζώο.prototype` console.log(Object.getPrototypeOf(Σκύλος.prototype) === Ζώο.prototype); // true
Βασικές έννοιες:
-
Αλυσίδα πρωτοτύπων: Η σύνδεση μεταξύ αντικειμένων μέσω του
[[Prototype]]. -
__proto__(παλαιότερο/μη τυπικό, αλλά χρήσιμο για κατανόηση): Ιδιότητα μέσω της οποίας μπορεί να αποκτήσει πρόσβαση στο[[Prototype]]. Δεν συνιστάται η χρήση σε παραγωγικό κώδικα. -
Object.getPrototypeOf(obj): Τυπικός τρόπος για να πάρει κανείς το πρωτότυπο ενός αντικειμένου. -
Object.setPrototypeOf(obj, proto): Τυπικός τρόπος για να αλλάξει κανείς το πρωτότυπο ενός αντικειμένου (δεν συνιστάται η αλλαγή του πρωτοτύπου σε ήδη υπάρχοντα αντικείμενα μετά τη δημιουργία τους). -
instanceof: Τελεστής για έλεγχο αν ένα αντικείμενο είναι παράδειγμα μιας κλάσης ή κατασκευαστικής συνάρτησης, μέσω ελέγχου της αλυσίδας πρωτοτύπων.console.log(οδυσσέας instanceof Σκύλος); // true console.log(οδυσσέας instanceof Ζώο); // true console.log(οδυσσέας instanceof Object); // true (στο τέλος της αλυσίδας είναι το `Object.prototype`) -
super: Χρησιμοποιείται σε κλάσεις για την κλήση μεθόδων ή του κατασκευαστή της γονικής κλάσης.
Η διαφορά μεταξύ κλασικής και κλασικής προσέγγισης: Οι κλάσεις παρέχουν έναν πιο δομημένο και συντακτικά άνετο τρόπο εργασίας με την πρωτοτυπική κληρονομιά, κοντά σε άλλες γλώσσες προγραμματισμού. Ωστόσο, ο βασικός μηχανισμός παραμένει ο ίδιος — η κληρονομιά μέσω πρωτοτύπων.