Πώς λειτουργεί το array.prototype.map ()

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

Με αυτό το πνεύμα, ας πάρουμε αυτό το επιπλέον βήμα σήμερα και να εξερευνήσουν μια πολύ δημοφιλής λειτουργία: Array.prototype.map().

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

Η map()μέθοδος δημιουργεί έναν νέο πίνακα με το αποτέλεσμα της κλήσης μιας παρεχόμενης συνάρτησης σε κάθε στοιχείο του πίνακα κλήσεων.

Παράδειγμα:

var array1 = [1, 4, 9, 16]; // pass a function to map const map1 = array1.map(x => x * 2); console.log(map1); // expected output: Array [2, 8, 18, 32]

Εκτέλεση

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

/*Array.prototype.map implementation*/ Array.prototype.map = function (callback/*, thisArg*/) { var T, A, k; if (this == null) { throw new TypeError('this is null or not defined'); } var O = Object(this); var len = O.length >>> 0; if (typeof callback !== 'function') { throw new TypeError(callback + ' is not a function'); } if (arguments.length > 1) { T = arguments[1]; } A = new Array(len); k = 0; while (k < len) { var kValue, mappedValue; if (k in O) { kValue = O[k]; mappedValue = callback.call(T, kValue, k, O); A[k] = mappedValue; } k++; } return A; };

Έχω επισημάνει μερικές κοινές ερωτήσεις που μπορεί να προκύψουν στα παρακάτω σχόλια κώδικα.

/*Array.prototype.map implementation*/ Array.prototype.map = function (callback/*, thisArg*/) { var T, A, k; if (this == null) { throw new TypeError('this is null or not defined'); } var O = Object(this); var len = O.length >>> 0;// QUESTION 1 : What is the need for this line of code? if (typeof callback !== 'function') { throw new TypeError(callback + ' is not a function'); } if (arguments.length > 1) { T = arguments[1]; } // QUESTION 2 :What is the need for the if condition and why are we assiging T=arguments[1]? A = new Array(len); k = 0; while (k < len) { var kValue, mappedValue; if (k in O) { kValue = O[k]; mappedValue = callback.call(T, kValue, k, O); // QUESTION 3: why do we pass T,k and O when all you need is kvalue? A[k] = mappedValue; } k++; } return A; };

Ας αντιμετωπίσουμε καθένα από τα κάτω

ΕΡΩΤΗΣΗ 3: Γιατί περνάμε T, k και O όταν το μόνο που χρειάζεστε είναι kValue;

mappedValue = callback.call(T, kValue, k, O);

Αυτή είναι η απλούστερη από τις τρεις ερωτήσεις, οπότε το έχω επιλέξει αρχικά. Στις περισσότερες περιπτώσεις, η μεταφορά του kValue στην επανάκληση θα ήταν αρκετή αλλά:

  • Τι γίνεται αν έχετε μια περίπτωση χρήσης όπου πρέπει να εκτελέσετε μια λειτουργία μόνο σε κάθε άλλο στοιχείο; Λοιπόν, χρειάζεστε ένα ευρετήριο που είναι (k) .
  • Παρομοίως, θα μπορούσαν να υπάρχουν και άλλες περιπτώσεις χρήσης στις οποίες χρειάζεστε τον πίνακα (O) για να είναι διαθέσιμος στην επανάκληση.
  • Γιατί Τ ; Προς το παρόν, απλώς ξέρετε ότι ο Τ μεταφέρεται για να διατηρήσει το περιβάλλον. Θα το καταλάβετε καλύτερα μόλις τελειώσετε με την ερώτηση 2.

ΕΡΩΤΗΣΗ 2: Ποια είναι η ανάγκη για τη συνθήκη if και γιατί εκχωρούμε T = ορίσματα [1];

if (arguments.length > 1) { T = arguments[1]; }

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

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

Για να διευκρινίσουμε καλύτερα, ας υποθέσουμε ότι έχετε μια ψεύτικη απαίτηση όπου πρέπει να επιστρέψετε τον αριθμό / 2 εάν διαιρείται με 2 και εάν δεν διαιρείται με 2, πρέπει να επιστρέψετε το όνομα χρήστη του καλούντος. Ο παρακάτω κώδικας δείχνει πώς μπορείτε να το κάνετε αυτό:

const myObj = { user: "John Smith" } var x = [10, 7]; let output = x.map(function (n) { if (n % 2 == 0) { return n / 2; } else { return this.user } }, myObj) // myObj is the second optional argument arguments[1] console.log(output); // [5,'John Smith'] //if you run the program without supplying myObj it would be //undefined as it cannot access myObj values console.log(output); // [ 5, undefined ]

ΕΡΩΤΗΣΗ 1: Ποια είναι η ανάγκη για αυτήν τη γραμμή κώδικα;

var len = O.length >>> 0

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

const anotherObject={length:{}} const myObj = { user: "John Smith" } var x = [10, 7]; let output = x.map.call(anotherObject,function (n) { if (n % 2 == 0) {return n / 2;} else {return this.user} }, myObj)

Όταν καλείτε χρησιμοποιώντας κλήση,η πρώτη παράμετρος θα είναι το πλαίσιο στο οποίο εκτελείται η λειτουργία χάρτη. Στέλνοντας την παράμετρο, αντικαθιστάτε το "αυτό" μέσα στο χάρτη με το "αυτό" ενός άλλου αντικειμένου.

Εάν παρατηρήσετε, η ιδιότητα μήκους του anotherObject είναι κενό αντικείμενο και όχι ακέραιος. Εάν χρησιμοποιείτε απλώς το O.length αντί του O.length> >> 0 θα έχει ως αποτέλεσμα μια απροσδιόριστη τιμή. Με μηδενική μετατόπιση, μετατρέπετε πραγματικά κλάσματα και μη ακέραιους σε ακέραιο. Σε αυτήν την περίπτωση το αποτέλεσμα θα εξαναγκασθεί στο 0.

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

ECMAScript Language Specification - ECMA-262 Έκδοση 5.1

Αυτό το έγγραφο και οι πιθανές μεταφράσεις του μπορούν να αντιγραφούν και να παρασχεθούν σε άλλους, και παράγωγα έργα που σχολιάζουν…

www.ecma-international.org

Η προδιαγραφή ( βήμα 3 ) λέει καθαρά ότι το μήκος πρέπει να είναι ακέραιος 32 bit χωρίς υπογραφή. Αυτός είναι ο λόγος που αλλάζουμε το μηδέν για να διασφαλίσουμε ότι το μήκος είναι ακέραιος, καθώς ο ίδιος ο χάρτης δεν απαιτεί η τιμή αυτή να είναι αντικείμενο Array.

Αυτό είναι!

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

Salathiel Genese, Jordan Harband - ευχαριστώ!

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

Σας ευχαριστούμε για τον χρόνο σας και την ευτυχή κωδικοποίηση!