Βρίσκοντας τον δρόμο σας με .Map ()

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

Το πρόβλημα

Φανταστείτε ότι έχετε έναν πίνακα και πρέπει να αλλάξετε κάθε στοιχείο στον πίνακα. Ίσως, για παράδειγμα, να πάρει μια σειρά από ύψη σε ίντσες και να χρειαστεί να τα μετατρέψετε σε εκατοστά. Ή πιθανώς μετατροπή μιας σειράς θερμοκρασιών σε Celcius σε Fahrenheit. Εάν είστε νέοι στον προγραμματισμό, το μυαλό σας μπορεί να πάει αμέσως σε κάποια μορφή βρόχου. Και μάντεψε τι? Είμαι βέβαιος ότι θα μπορούσατε να το κάνετε να λειτουργήσει.

Ωστόσο, είμαι εδώ για να σας δώσει ένα ακόμη εργαλείο - κάτι για να σας πάρει λίγο πιο κοντά στην κομψή: Array.prototype.map().

Η mapμέθοδος μας επιτρέπει να μετατρέπουμε κάθε στοιχείο ενός πίνακα, χωρίς να επηρεάζουμε τον αρχικό πίνακα. Θεωρείται συνάρτηση υψηλότερης τάξης και τεχνική λειτουργικού προγραμματισμού επειδή παίρνει μια συνάρτηση ως επιχείρημα και εκτελούμε υπολογισμό χωρίς να μεταλλάξουμε την κατάσταση της εφαρμογής μας.

Mapείναι μια ιδιότητα που κληρονομείται από το πρωτότυπο πίνακα. Τα πρωτότυπα παρέχουν ενσωματωμένες μεθόδους που συνοδεύουν αντικείμενα (οι πίνακες είναι ειδικοί τύποι αντικειμένων στα μάτια της JavaScript). Ενώ mapμπορεί να είναι λίγο πιο ξένο, αυτό το πρωτότυπο δεν διαφέρει από, για παράδειγμα, το Array.lengthπρωτότυπο. Αυτές είναι απλώς μέθοδοι που ενσωματώνονται σε JavaScript. Τα πρωτότυπα συστοιχιών μπορούν να προστεθούν και να μεταλλαχθούν με: Array.prototype.= ...

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

Τι κάνει λοιπόν το .map ();

Ας υποθέσουμε ότι έχετε μια σειρά θερμοκρασιών σε Κελσίου που θέλετε να μετατρέψετε σε Φαρενάιτ.

Υπάρχουν διάφοροι τρόποι επίλυσης αυτού του προβλήματος. Ένας τρόπος μπορεί να είναι να γράψετε έναν forβρόχο για να δημιουργήσετε μια σειρά από θερμοκρασίες Φαρενάιτ από τις δεδομένες θερμοκρασίες Κελσίου.

Με το forβρόχο μπορεί να γράψουμε:

const celciusTemps = [22, 36, 71, 54]; const getFahrenheitTemps = (function(temp) { const fahrenheitTemps = []; for (let i = 0; i < celciusTemps.length; i += 1) { temp = celciusTemps[i] * (9/5) + 32 fahrenheitTemps.push(temp); } console.log(fahrenheitTemps); [71.6, 96.8, 159.8, 129.2 })();

Δυο πράγματα που πρέπει να σημειώσετε:

  1. Δουλεύει.
  2. Χρησιμοποιούμε μια έκφραση άμεσης επίκλησης λειτουργίας (IIFE) για να αποφύγουμε επίσης να καλέσουμε τη συνάρτηση.
  3. Είναι λίγο ρητό και όχι πολύ κομψό.

Map μας επιτρέπει να πάρουμε τον παραπάνω κώδικα και να τον αναπαράγουμε στα ακόλουθα:

const fahrenheitTemps = celciusTemps.map(e => e * (9/5) + 32); console.log(fahrenheitTemps); // [71.6, 96.8, 159.8, 129.2]

Πώς λειτουργεί λοιπόν ο χάρτης;

Mapπαίρνει μια συνάρτηση και εφαρμόζει αυτήν τη συνάρτηση σε κάθε στοιχείο του πίνακα. Θα μπορούσαμε να γράψουμε mapλίγο περισσότερο με το ES5 για να το δούμε λίγο πιο καθαρά.

const fahrenheitTemps = celciusTemps .map(function(elementOfArray) { return elementOfArray * (9/5) + 32; }); console.log(fahrenheitTemps); // [71.6, 96.8, 159.8, 129.2]

Εάν η λειτουργία χάρτη μας θα μπορούσε να πει τι κάνει, θα έλεγε:

"Για κάθε στοιχείο του πίνακα, το πολλαπλασιάζω με (9/5) και μετά προσθέτω 32. Όταν γίνει αυτό, επιστρέφω το αποτέλεσμα ως στοιχείο σε έναν νέο πίνακα που ονομάζεται fahrenheitTemps."

Ας δούμε μια πιο κοινή περίπτωση χρήσης. Ας υποθέσουμε ότι έχουμε μια σειρά peopleαντικειμένων. Κάθε αντικείμενο έχει nameκαι ageτιμή-κλειδί ζεύγους. Θέλουμε να δημιουργήσουμε μια μεταβλητή που να είναι μόνο τα ονόματα όλων των πινάκων. Με τη forμέθοδο βρόχου μας μπορεί να γράψουμε:

const people = [ {name: Steve, age: 32}, {name: Mary, age: 28}, {name: Bill, age: 41}, ]; const getNames = (function(person) { const names = []; for (let i = 0; i < people.length; i += 1) { name = people[i].name; names.push(name); } console.log(names); // [Steve, Mary, Bill]; })();

Με map:

const names = people.map(e => e.name); console.log(names) // [Steve, Mary, Bill];

Παρατηρήστε εδώ ότι δεν μεταμορφώνουμε τίποτα, απλώς επιστρέφουμε το ζεύγος κλειδιού-τιμής name.

Και πάλι, οι forβρόχοι λειτουργούν. Όμως, είναι ρητό και πρέπει να δημιουργούμε μια νέα προσαρμοσμένη συνάρτηση κάθε φορά που θέλουμε να κάνουμε διαφορετικό μετασχηματισμό. Ένα βασικό μέρος του προγραμματισμού είναι να γράφετε DRY κώδικα (Μην επαναλαμβάνετε τον εαυτό σας). Αυτές οι λειτουργίες υψηλότερης τάξης, όπως ο χάρτης, μας επιτρέπουν να κάνουμε πιο περίπλοκο προγραμματισμό σε λιγότερες γραμμές κώδικα από ότι θα μπορούσαμε χωρίς αυτές.

Ανακαλύπτοντας τον τροχό:

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

Πρώτον, για να επισυνάψετε μια πρωτότυπη μέθοδο σε ένα Array, θα γράψουμε:

Array.prototype.

έτσι για εμάς:

Array.prototype.myMap =

Όμως, ποιος θα είναι ο κωδικός μας;

Έχουμε ήδη τη λογική που χρειαζόμαστε από τους forπαραπάνω βρόχους. Το μόνο που πρέπει να κάνουμε είναι να το αναπαράγουμε λίγο. Ας αναδιαμορφώσουμε την τελευταία συνάρτηση που γράψαμε getNames().

Θυμηθείτε, αυτή η συνάρτηση πήρε ένα άτομο (με άλλα λόγια ένα στοιχείο του πίνακα μας), έκανε μια προσαρμοσμένη μετατροπή σε αυτό το στοιχείο (με το forβρόχο και κάποια λογική), και επέστρεψε έναν πίνακα ονομάτων (ή ενός νέου πίνακα).

const getNames = (function(person) { const names = []; for (let i = 0; i < people.length; i += 1) { name = people[i].name; names.push(name); } console.log(names); // [Steve, Mary, Bill]; })();

Αρχικά, ας αλλάξουμε το όνομα της λειτουργίας μας. Σε τελική ανάλυση, αυτή η νέα μέθοδος δεν προϋποθέτει να ξέρει τι είδους πίνακα θα ενεργεί:

const myMap = (function(person) { //Changed name const names = []; for (let i = 0; i < people.length; i += 1) { name = people[i].name; names.push(name); } console.log(names); // [Steve, Mary, Bill]; })();

Δεύτερον, δημιουργούμε τη δική μας έκδοση του .map(). Γνωρίζουμε ότι αυτό θα πάρει μια λειτουργία που παρέχει ο χρήστης. Ας αλλάξουμε την παράμετρο που παίρνει η λειτουργία μας:

// It is a bit verbose, but a very clear parameter name const myMap = (function(userProvidedFunction) { const names = []; for (let i = 0; i < people.length; i += 1) { name = people[i].name; names.push(name); } console.log(names); // [Steve, Mary, Bill]; })();

Τέλος, δεν έχουμε ιδέα σε ποιον πίνακα θα ενεργήσει αυτή η μέθοδος. Έτσι, δεν μπορούμε να αναφερθούμε people.lengthαλλά μπορούμε να αναφερθούμε this.length. this, θα επιστρέψει τον πίνακα στην οποία ενεργεί η μέθοδος. Επίσης, ας καθαρίσουμε μερικά από τα άλλα ονόματα μεταβλητών:

const myMap = (function(userProvidedFunction) { // change variable name const newArr = []; // use "this.length" for (let i = 0; i < this.length; i += 1) { // use "this[i]", and change variable name const newElement = this[i]; // update the array we push into newArr.push(newElement); } // Return the newly created array return newArr; })();

Είμαστε σχεδόν εκεί, αλλά υπάρχει ένα πράγμα που ξεχνάμε. Δεν έχουμε μεταμορφώσει τον πίνακα! Το μόνο που κάναμε παραπάνω είναι να επιστρέψουμε τον παλιό πίνακα. Πρέπει να εφαρμόσουμε τη συνάρτηση που παρέχεται από τον χρήστη σε κάθε στοιχείο του πίνακα:

const myMap = (function(userProvidedFunction) { const newArr = []; for (let i = 0; i < this.length; i += 1) { /* Transform the element by passing it into the * user-provided function */ const newElement = userProvidedFunction(this[i]); newArr.push(newElement); } return newArr; })();

Τέλος, μπορούμε να επισυνάψουμε τη νέα μας λειτουργία Array.prototype.

Array.prototype.myMap = myMap;

Ένας τελικός έλεγχος υγιεινής:

const myArray = [1, 2, 3]; // Multiply each element x 2 const myMappedArray = myArray.myMap(e => e * 2) console.log(myMappedArray) // [2, 4, 6];

Περίληψη

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

Ευχαριστώ για την ανάγνωση!

ουζ