Η επανάληψη σε συλλογές δεδομένων χρησιμοποιώντας παραδοσιακούς βρόχους μπορεί γρήγορα να γίνει δυσκίνητη και αργή, ειδικά όταν πρόκειται για τεράστιο όγκο δεδομένων.
Τα JavaScript Generators και Iterators παρέχουν μια λύση για αποτελεσματική επανάληψη σε μεγάλες συλλογές δεδομένων. Χρησιμοποιώντας τα, μπορείτε να ελέγξετε τη ροή επανάληψης, να αποδώσετε τις τιμές μία κάθε φορά και να διακόψετε και να συνεχίσετε τη διαδικασία επανάληψης.
Εδώ θα καλύψετε τα βασικά και εσωτερικά ενός επαναλήπτη JavaScript και πώς μπορείτε να δημιουργήσετε έναν επαναλήπτη χειροκίνητα και χρησιμοποιώντας μια γεννήτρια.
JavaScript Iterators
Ένας επαναλήπτης είναι ένα αντικείμενο JavaScript που υλοποιεί το πρωτόκολλο iterator. Αυτά τα αντικείμενα το κάνουν έχοντας ένα Επόμενο μέθοδος. Αυτή η μέθοδος επιστρέφει ένα αντικείμενο που υλοποιεί το IteratorResult διεπαφή.
ο IteratorResult Η διεπαφή περιλαμβάνει δύο ιδιότητες: Έγινε και αξία. ο Έγινε Η ιδιότητα είναι ένα boolean που επιστρέφει ψευδής εάν ο επαναλήπτης μπορεί να παράγει την επόμενη τιμή στην ακολουθία του ή αληθής εάν ο επαναλήπτης έχει ολοκληρώσει την ακολουθία του.
ο αξία Η ιδιότητα είναι μια τιμή JavaScript που επιστρέφεται από τον επαναλήπτη κατά τη διάρκεια της ακολουθίας του. Όταν ένας επαναλήπτης ολοκληρώσει την ακολουθία του (όταν Έγινεαληθής), αυτή η ιδιότητα επιστρέφει απροσδιόριστος.
Όπως υποδηλώνει το όνομα, οι επαναληπτικοί σάς επιτρέπουν να "επαναλαμβάνετε" πάνω από αντικείμενα JavaScript, όπως πίνακες ή χάρτες. Αυτή η συμπεριφορά είναι δυνατή λόγω του επαναληπτικού πρωτοκόλλου.
Στο JavaScript, το επαναληπτικό πρωτόκολλο είναι ένας τυπικός τρόπος ορισμού αντικειμένων που μπορείτε να επαναλάβετε, όπως σε ένα για...του βρόχος.
Για παράδειγμα:
συνθ φρούτα = ["Μπανάνα", "Μάνγκο", "Μήλο", "σταφύλια"];
Για (συνθ επαναλήπτης του φρούτα) {
κονσόλα.log (επαναλήπτης);
}
/*
Μπανάνα
Μάνγκο
μήλο
σταφύλια
*/
Αυτό το παράδειγμα επαναλαμβάνεται πάνω από το φρούτα πίνακας χρησιμοποιώντας α για...του βρόχος. Σε κάθε επανάληψη καταγράφει την τρέχουσα τιμή στην κονσόλα. Αυτό είναι δυνατό επειδή οι πίνακες είναι επαναλαμβανόμενοι.
Ορισμένοι τύποι JavaScript, όπως Arrays, String, Σύνολα και Χάρτες, είναι ενσωματωμένες επαναλήψεις επειδή (ή ένα από τα αντικείμενα στην πρωτότυπη αλυσίδα τους) υλοποιούν ένα @@iterator μέθοδος.
Άλλοι τύποι, όπως τα Αντικείμενα, δεν επαναλαμβάνονται από προεπιλογή.
Για παράδειγμα:
συνθ iterObject = {
αυτοκίνητα: ["Τέσλα", "BMW", "Toyota"],
των ζώων: ["Γάτα", "Σκύλος", "Χάμστερ"],
τροφή: ["Μπέργκερ", "Πίτσα", "Ζυμαρικά"],
};Για (συνθ επαναλήπτης του iterObject) {
κονσόλα.log (επαναλήπτης);
}
// TypeError: Το iterObject δεν μπορεί να επαναληφθεί
Αυτό το παράδειγμα δείχνει τι συμβαίνει όταν προσπαθείτε να επαναλάβετε ένα αντικείμενο που δεν είναι επαναλήψιμο.
Κάνοντας ένα αντικείμενο επαναλαμβανόμενο
Για να κάνετε ένα αντικείμενο επαναλαμβανόμενο, πρέπει να εφαρμόσετε ένα Σύμβολο.επαναλήπτης μέθοδος στο αντικείμενο. Για να γίνει επαναληπτική, αυτή η μέθοδος πρέπει να επιστρέψει ένα αντικείμενο που υλοποιεί το IteratorResult διεπαφή.
ο Σύμβολο.επαναλήπτης σύμβολο εξυπηρετεί τον ίδιο σκοπό με @@iterator και μπορεί να χρησιμοποιηθεί εναλλακτικά στην "προδιαγραφή" αλλά όχι στον κώδικα ως @@iterator δεν είναι έγκυρη σύνταξη JavaScript.
Τα παρακάτω μπλοκ κώδικα παρέχουν ένα παράδειγμα του τρόπου με τον οποίο μπορείτε να κάνετε ένα αντικείμενο επαναληπτικό χρησιμοποιώντας το iterObject.
Αρχικά, προσθέστε το Σύμβολο.επαναλήπτης μέθοδος για να iterObject χρησιμοποιώντας μια συνάρτηση δήλωση.
Όπως έτσι:
iterObject[Σύμβολο.iterator] = λειτουργία () {
// Τα επόμενα μπλοκ κώδικα πηγαίνουν εδώ...
}
Στη συνέχεια, θα χρειαστεί να αποκτήσετε πρόσβαση σε όλα τα κλειδιά του αντικειμένου που θέλετε να κάνετε επαναληπτικό. Μπορείτε να αποκτήσετε πρόσβαση στα κλειδιά χρησιμοποιώντας το Αντικείμενο.κλειδιά μέθοδος, η οποία επιστρέφει έναν πίνακα με τις αναρίθμητες ιδιότητες ενός αντικειμένου. Για να επιστρέψετε μια σειρά από iterObjectκλειδιά του, περάστε το Αυτό λέξη-κλειδί ως επιχείρημα για Αντικείμενο.κλειδιά.
Για παράδειγμα:
αφήνω objProperties = Αντικείμενο.keys(Αυτό)
Η πρόσβαση σε αυτόν τον πίνακα θα σας επιτρέψει να ορίσετε τη συμπεριφορά επανάληψης του αντικειμένου.
Στη συνέχεια, πρέπει να παρακολουθείτε τις επαναλήψεις του αντικειμένου. Μπορείτε να το επιτύχετε αυτό χρησιμοποιώντας μεταβλητές μετρητή.
Για παράδειγμα:
αφήνω ιδιότητα Ευρετήριο = 0;
αφήνω παιδίΔείκτης = 0;
Θα χρησιμοποιήσετε την πρώτη μεταβλητή μετρητή για να παρακολουθείτε τις ιδιότητες του αντικειμένου και τη δεύτερη για να παρακολουθείτε τα παιδιά της ιδιότητας.
Στη συνέχεια, θα πρέπει να εφαρμόσετε και να επιστρέψετε το Επόμενο μέθοδος.
Όπως έτσι:
ΕΠΙΣΤΡΟΦΗ {
Επόμενο() {
// Τα επόμενα μπλοκ κώδικα πηγαίνουν εδώ...
}
}
μεσα στην Επόμενο μέθοδο, θα χρειαστεί να χειριστείτε μια περίπτωση ακμής που εμφανίζεται όταν ολόκληρο το αντικείμενο έχει επαναληφθεί. Για να χειριστείτε το περίβλημα άκρων, πρέπει να επιστρέψετε ένα αντικείμενο με το αξία οριστεί σε απροσδιόριστος και Έγινε οριστεί σε αληθής.
Εάν αυτή η περίπτωση δεν αντιμετωπιστεί, η προσπάθεια επανάληψης πάνω από το αντικείμενο θα έχει ως αποτέλεσμα έναν άπειρο βρόχο.
Δείτε πώς να χειριστείτε την θήκη:
αν (ευρετήριο ιδιοκτησίας > objΙδιότητες.μήκος- 1) {
ΕΠΙΣΤΡΟΦΗ {
αξία: απροσδιόριστος,
Έγινε: αληθής,
};
}
Στη συνέχεια, θα χρειαστεί να αποκτήσετε πρόσβαση στις ιδιότητες του αντικειμένου και στα θυγατρικά τους στοιχεία χρησιμοποιώντας τις μεταβλητές μετρητή που δηλώσατε νωρίτερα.
Όπως έτσι:
// Πρόσβαση στις ιδιότητες γονέα και θυγατρικού
συνθ ιδιότητες = Αυτό[objProperties[propertyIndex]];
συνθ ιδιοκτησία = ιδιότητες[childIndex];
Στη συνέχεια, πρέπει να εφαρμόσετε κάποια λογική για την αύξηση των μεταβλητών του μετρητή. Η λογική πρέπει να επαναφέρει το παιδίΕυρετήριο όταν δεν υπάρχουν άλλα στοιχεία στον πίνακα μιας ιδιότητας και μετακινούνται στην επόμενη ιδιότητα του αντικειμένου. Επιπλέον, θα πρέπει να αυξηθεί παιδίΕυρετήριο, εάν εξακολουθούν να υπάρχουν στοιχεία στον πίνακα της τρέχουσας ιδιότητας.
Για παράδειγμα:
// Λογική αύξησης δείκτη
if (childIndex >= properties.length - 1) {
// εάν δεν υπάρχουν άλλα στοιχεία στον θυγατρικό πίνακα
// επαναφοράπαιδίδείκτης
παιδίΔείκτης = 0;
// Μετακίνηση στην επόμενη ιδιότητα
propertyIndex++;
} αλλού {
// Μετακίνηση στο επόμενο στοιχείο του θυγατρικού πίνακα
παιδίΕυρετήριο++
}
Τέλος, επιστρέψτε ένα αντικείμενο με το Έγινε ιδιοκτησία ορίζεται σε ψευδής και το αξία η ιδιότητα ορίζεται στο τρέχον θυγατρικό στοιχείο στην επανάληψη.
Για παράδειγμα:
ΕΠΙΣΤΡΟΦΗ {
Έγινε: ψευδής,
αξία: ιδιοκτησία,
};
Ολοκληρώθηκες Σύμβολο.επαναλήπτης Η λειτουργία πρέπει να είναι παρόμοια με το μπλοκ κώδικα παρακάτω:
iterObject[Σύμβολο.iterator] = λειτουργία () {
συνθ objProperties = Αντικείμενο.keys(Αυτό);
αφήνω ιδιότητα Ευρετήριο = 0;
αφήνω παιδίΔείκτης = 0;ΕΠΙΣΤΡΟΦΗ {
Επόμενο: () => {
//Χειρισμός θήκης άκρων
αν (ευρετήριο ιδιοκτησίας > objΙδιότητες.μήκος- 1) {
ΕΠΙΣΤΡΟΦΗ {
αξία: απροσδιόριστος,
Έγινε: αληθής,
};
}// Πρόσβαση στις ιδιότητες γονέα και θυγατρικού
συνθ ιδιότητες = Αυτό[objProperties[propertyIndex]];
συνθ ιδιοκτησία = ιδιότητες[childIndex];// Λογική αύξησης δείκτη
if (childIndex >= properties.length - 1) {
// εάν δεν υπάρχουν άλλα στοιχεία στον θυγατρικό πίνακα
// επαναφοράπαιδίδείκτης
παιδίΔείκτης = 0;
// Μετακίνηση στην επόμενη ιδιότητα
propertyIndex++;
} αλλού {
// Μετακίνηση στο επόμενο στοιχείο του θυγατρικού πίνακα
παιδίΕυρετήριο++
}
ΕΠΙΣΤΡΟΦΗ {
Έγινε: ψευδής,
αξία: ιδιοκτησία,
};
},
};
};
Τρέξιμο α για...του βρόχο επάνω iterObject μετά από αυτήν την υλοποίηση δεν θα προκαλέσει σφάλμα καθώς υλοποιεί α Σύμβολο.επαναλήπτης μέθοδος.
Η μη αυτόματη εφαρμογή επαναλήψεων, όπως κάναμε παραπάνω, δεν συνιστάται καθώς είναι επιρρεπής σε σφάλματα και η διαχείριση της λογικής μπορεί να είναι δύσκολη.
Γεννήτριες JavaScript
Μια γεννήτρια JavaScript είναι μια συνάρτηση που μπορείτε να διακόψετε και να συνεχίσετε την εκτέλεσή της ανά πάσα στιγμή. Αυτή η συμπεριφορά του επιτρέπει να παράγει μια ακολουθία τιμών με την πάροδο του χρόνου.
Μια συνάρτηση γεννήτριας, η οποία είναι μια συνάρτηση που επιστρέφει μια γεννήτρια, παρέχει μια εναλλακτική λύση στη δημιουργία επαναληπτικών.
Μπορείτε να δημιουργήσετε μια συνάρτηση γεννήτριας με τον ίδιο τρόπο που θα δημιουργήσατε μια δήλωση συνάρτησης σε JavaScript. Η μόνη διαφορά είναι ότι πρέπει να προσθέσετε έναν αστερίσκο (*) στη λέξη-κλειδί συνάρτησης.
Για παράδειγμα:
λειτουργία* παράδειγμα () {
ΕΠΙΣΤΡΟΦΗ"Γεννήτρια"
}
Όταν καλείτε μια κανονική συνάρτηση σε JavaScript, επιστρέφει την τιμή που καθορίζεται από αυτήν ΕΠΙΣΤΡΟΦΗ λέξη-κλειδί ή απροσδιόριστος σε διαφορετική περίπτωση. Αλλά μια συνάρτηση γεννήτριας δεν επιστρέφει καμία τιμή αμέσως. Επιστρέφει ένα αντικείμενο Generator, το οποίο μπορείτε να αντιστοιχίσετε σε μια μεταβλητή.
Για πρόσβαση στην τρέχουσα τιμή του επαναλήπτη, καλέστε το Επόμενο μέθοδο στο αντικείμενο Generator.
Για παράδειγμα:
συνθ gen = example();
console.log (gen.next()); // { αξία: 'Γεννήτρια', Έγινε: αληθής }
Στο παραπάνω παράδειγμα, το αξία περιουσία προήλθε από α ΕΠΙΣΤΡΟΦΗ λέξη-κλειδί, τερματίζοντας ουσιαστικά τη γεννήτρια. Αυτή η συμπεριφορά είναι γενικά ανεπιθύμητη με τις λειτουργίες γεννήτριας, καθώς αυτό που τις διακρίνει από τις κανονικές συναρτήσεις είναι η δυνατότητα παύσης και επανεκκίνησης της εκτέλεσης.
Η λέξη-κλειδί απόδοσης
ο απόδοση παραγωγής Η λέξη-κλειδί παρέχει έναν τρόπο επανάληψης μεταξύ των τιμών στις γεννήτριες παύοντας την εκτέλεση μιας συνάρτησης γεννήτριας και επιστρέφοντας την τιμή που την ακολουθεί.
Για παράδειγμα:
λειτουργία* παράδειγμα() {
απόδοση παραγωγής"Μοντέλο S"
απόδοση παραγωγής"Μοντέλο Χ"
απόδοση παραγωγής"Cyber Truck"ΕΠΙΣΤΡΟΦΗ"Τέσλα"
}συνθ gen = example();
console.log (gen.next()); // { αξία: 'Μοντέλο S', Έγινε: ψευδής }
Στο παραπάνω παράδειγμα, όταν το Επόμενο καλείται η μέθοδος παράδειγμα γεννήτρια, θα σταματάει κάθε φορά που συναντά το απόδοση παραγωγής λέξη-κλειδί. ο Έγινε ιδιοκτησία θα οριστεί επίσης σε ψευδής μέχρι να συναντήσει ένα ΕΠΙΣΤΡΟΦΗ λέξη-κλειδί.
Καλώντας το Επόμενο μέθοδο πολλές φορές στο παράδειγμα γεννήτρια για να το αποδείξετε, θα έχετε ως έξοδο το εξής.
console.log (gen.next()); // { αξία: "Μοντέλο Χ", Έγινε: ψευδής }
console.log (gen.next()); // { αξία: «Cyber Truck», Έγινε: ψευδής }
console.log (gen.next()); // { αξία: «Τέσλα», Έγινε: αληθής }
κονσόλα.log (gen.next()); // { value: undefined, done: true }
Μπορείτε επίσης να κάνετε επανάληψη σε ένα αντικείμενο Generator χρησιμοποιώντας το για...του βρόχος.
Για παράδειγμα:
Για (συνθ επαναλήπτης του γεν) {
κονσόλα.log (επαναλήπτης);
}
/*
Μοντέλο Σ
Μοντέλο Χ
Φορτηγό Cyber
*/
Χρήση Iterators και Generators
Αν και οι επαναλήψεις και οι γεννήτριες μπορεί να φαίνονται σαν αφηρημένες έννοιες, δεν είναι. Μπορούν να είναι χρήσιμα όταν εργάζεστε με άπειρες ροές δεδομένων και συλλογές δεδομένων. Μπορείτε επίσης να τα χρησιμοποιήσετε για να δημιουργήσετε μοναδικά αναγνωριστικά. Οι βιβλιοθήκες κρατικής διαχείρισης, όπως η MobX-State-Tree (MST) τις χρησιμοποιούν επίσης κάτω από την κουκούλα.