Μέθοδοι λειτουργίας Javascript: Κλήση vs Εφαρμογή εναντίον δεσμού

Οι λειτουργίες Javascript έχουν αυτές τις τρεις μεθόδους: Call (), apply () και bind (). Έχουν περισσότερες μεθόδους που θα αγνοήσω. Μην ανησυχείτε, θα χρησιμοποιήσετε αυτά τα τρία περισσότερο.

π.χ.: someFunc.call ()

Τα βασικά: Κλήση εναντίον Εφαρμογή

Τι κάνουν αυτές οι μέθοδοι; Χαίρομαι που ρωτήσατε. Εξετάστε πώς οι ακόλουθες τρεις επικλήσεις οδηγούν σε όμοια παραγωγή:

var printTwo = συνάρτηση () {
 console.log (2).
},
printTwo (); // 2
printTwo.call (); // 2
printTwo.apply (); // 2

Οι κλήσεις και οι εφαρμογές είναι πολύ παρόμοιες: αμφότερες επικαλούνται τη λειτουργία που καλούνται και παίρνουν ένα 'αυτό' επιχείρημα ως το πρώτο τους επιχείρημα. Θα μιλήσω γι 'αυτό σύντομα.

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

(1, 2, 3) VS someFunc.apply (thisArg, [1, 2, 3])

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

var someFunc = λειτουργία () {
 επιστρέψτε αυτό το μήκος
}}

Με το παραπάνω παράδειγμα, someFunc.apply ([1, 2, 3]) θα επέστρεφαν 3 και έτσι θα κάποιεςFunc.call ([1, 2, 3]). Αυτό συμβαίνει επειδή κάθε κλήση είναι ισοδύναμη με:

[1, 2, 3] .someFunc (); // 3

Ωστόσο, someFunc () που επικαλείται χωρίς ειδική δέσμευση γι 'αυτό θα επέστρεφε undefined, επειδή αυτή είναι δεσμευμένη στο αντικείμενο παραθύρου από προεπιλογή.

Προεπιλεγμένη δέσμευση του "αυτού"

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

Τέλος πάντων, το call () και το apply () μπορεί να είναι πολύ χρήσιμο. Εάν έχετε έναν πίνακα που θέλετε να περάσετε ως χωριστά επιχειρήματα σε κάποια λειτουργία, μπορείτε να το κάνετε αυτό:

someFunc.apply (μηδέν, πίνακας);

Sidenote: υπάρχει κάποια πολύ δροσερή σύνταξη ES6, ο υπόλοιπος χειριστής, που σας επιτρέπει να επιτύχετε το ίδιο αποτέλεσμα με την εξάπλωση ενός πίνακα σε μια κλήση λειτουργίας:

someFunc (... array) // ίδιο αποτέλεσμα με το προηγούμενο παράδειγμα

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

var dog = {
 θόρυβος: "arf",
 Μιλήστε: λειτουργία () {
 console.log (this.noise)
 }}
},
var cat = {
 θόρυβος: "miaow"
},
dog.speak.call (γάτα); // Νιάου
Αλλά αυτή η τελευταία γραμμή είναι πολύ άσχημη. Αντ 'αυτού θα μπορούσαμε να κάνουμε:
cat.speak = dog.speak;
cat.speak (); //Νιάου

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

Χρησιμοποιώντας τη μέθοδο δέσμευσης

Ας πούμε ότι θέλουμε η γάτα να μιλήσει μέσα σε ένα δευτερόλεπτο. Εύκολα, θα χρησιμοποιήσουμε το setTimeout () του JavaScript.

setTimeout (cat.speak, 1000). // (παρέλθει ένα δευτερόλεπτο ...) απροσδιόριστο

Ωχ! Η γάτα δεν έπεσε. Γιατί είναι αυτό; Ας προσπαθήσουμε να το καταλάβουμε. Φαίνεται πως δώσαμε setTimeout την έκδοση της γάτας (). Αλλά τι περάσαμε πραγματικά; Απλά η λειτουργία ομιλίας (). Όταν το setTimeout το επαναλαμβάνει αργότερα, δεν θα υπάρχει κουκκίδα ώρας κλήσης προς τα αριστερά ή οποιοδήποτε σχετικό αντικείμενο για να το αναφερθούμε, έτσι αντίθετα αυτό θα αναφέρεται σε κάτι άχρηστο (για εμάς).

Το Bind () μπορεί να έρθει στη διάθεσή μας εδώ. Αυτό που κάνει είναι να επιστρέψει μια συνάρτηση που δεσμεύεται με το όρισμα που μεταβιβάζεται σε αυτό όταν καλείται.

setTimeout (cat.speak.bind (cat), 1000). // (ένα δευτερόλεπτο περνάει ...)

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

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

συμπέρασμα

Το Bind μπορεί να κάνει πολύ περισσότερα και η σελίδα MDN στο Function.prototype.bind () είναι ένα εξαιρετικό μέρος για να ξεκινήσετε. Στην πραγματικότητα, το MDN είναι συχνά ένα καλό μέρος για να ξεκινήσετε.

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

Τελικό Sidenote: Το ES6 είναι πραγματικά δροσερό. Λατρεύω τις λειτουργίες βελών του, οι οποίες μπορούν να λύσουν το πρόβλημα setTimeout παραπάνω χωρίς τη μέθοδο δέσμευσης. Συστήνω ιδιαίτερα να μάθω για το ES6 / ES2017.

Πρόσφατα άρχισα να παίζω με Observed Notebooks. Είναι φοβερό! Έκανα μια διαδραστική επίδειξη του χρόνου και της πολυπλοκότητας του χώρου κατά τον υπολογισμό των αριθμών του Fibonacci.

Το ObservationHQ δεν έχει σχόλια ως προς αυτό το γράψιμο, αλλά επιστρέψτε εδώ και πείτε μου τι σκέφτεστε :)