slevinkelevra Δημοσ. 31 Μαρτίου 2014 Δημοσ. 31 Μαρτίου 2014 Καλησπέρα και πάλι. Έχω ξαναπιάσει javascript για να θυμηθώ τα βασικά, να τεσταρω και να τη καταλαβω καλυτερα. Έπεσα πάνω στην bind(). Η αλήθεια είναι οτι κατάφερε να με κάνει να νιώσω στόκος. Καταρχάς ρε παιδιά, που χρησιμέυει? Δεν ειναι λιγο overkill? Ας πούμε οτι έχω το παρακάτω snipet function addLoadListener(fn){ window.addEventListener('load', fn, false); } addLoadListener(saySomething(4)); var boundHandler = saySomething.bind(null); addLoadListener(boundHandler(425)); function saySomething(message) { alert(message); } Η addLoadListener "προσθέτει" functions που εκτελούνται κατα το window onload. (μια εναλακτική του να προσθετεις 500 functions μεσα στο window onload). Η saySomething αρχικα μπαινει στην addLoadListener και βγαζει 4 κατα το on load. Και παω και κανω την boundHandler bind στην saySomething και βγαζει 425 παλι κατα το on load. Οπως και θα επρεπε...ΟΚ, overkill ομως γιατι θα μπορουσα να πω απλα addLoadListener(saySomething(4)); addLoadListener(saySomething(425)); και να εχω το ιδιο αποτελεσμα. Θα μου πεις, στο συγκεκριμένο παράδειγμα ειναι overkill, αλλου είναι χρήσιμή. ΟΚ, που όμως ρε παιδιά? Δεν μπορω να σκεφτω περιπτώσεις. Υπαρχει καποιος να μου εξηγησει λιγο? Also...ειδα Site: αυτό .Στο παραδειγμα που εχει στο "Creating a bound function" με το ποτε ειναι το Χ 9 και ποτε 81... μου κανει παλι λιγο overkill για τους παραπανω λογους και επισης δεν καταλαβαινω τη διαφορα module.getX() και module.getX. Βασικα δεν καταλαβαινω γιατι αυτο var getX = module.getX; getX(); βγαζει 9.Πως κολλαει με το global x και βγαζει 9? Το ξερω οτι ειναι φιλοσοφικο το θεμα αλλα δεν εχω ποιον αλλον να ρωτησω. Οποιος εχει ορεξη να μου εξηγησει , ευπροσδεκτος. Ευχαριστω πολυ
defacer Δημοσ. 1 Απριλίου 2014 Δημοσ. 1 Απριλίου 2014 Πρώτα πρέπει να έχεις υπόψη πώς ακριβώς δουλεύει το this στη JavaScript. Μια καλή και εύκολη απλοποίηση είναι η εξής: το this γενικά όπου εμφανίζεται αναφέρεται στο λεγόμενο "global object" -- το οποίο στην περίπτωση του browser είναι το window -- εκτός από την περίπτωση που εμφανίζεται μέσα σε μια function, στην οποία περίπτωση εάν η κλήση της έγινε από ένα expression του τύπου obj.method() τότε το this αναφέρεται στο obj που είδαμε πριν, διαφορετικά και πάλι είναι το global object. Υπάρχουν και κάποιες άλλες εξαιρέσεις αλλά κράτα αυτό για αρχή. Τώρα ξέρεις γιατί δουλεύει αυτό: var obj = { getValue: function() { return this.myValue; }, myValue: 42 }; obj.getValue(); // 42 γιατί το this γίνεται obj Αλλά δες τι μπορεί να γίνει στη συνέχεια. Αν αποθηκεύσεις τη function getValue σε μια άλλη μεταβλητή και μετά την καλέσεις: var getValue = obj.getValue; getValue(); // undefined?!?!? τότε η σύνταξη που χρησιμοποίησες κατά την κλήση ("getValue()") δεν ήταν της μορφής foo.bar() οπότε το this παρέμεινε να δείχνει στο global object. Γι' αυτό τελικά το αποτέλεσμα ήταν η τιμή του window.myValue, η οποία είναι undefined. Αν μετά δοκιμάσεις να δώσεις μια τιμή στο window.myValue και ξανακαλέσεις την getValue() τότε θα δεις αυτή την τιμή που έβαλες. Όλα αυτά εξαιτίας του πώς παίρνει τιμή το this ανάλογα με το πως καλείς τη συνάρτηση. Τώρα, μία από τις εξαιρέσεις που υπάρχουν για το this είναι η bind (άλλες πολύ συνηθισμένες είναι οι συναρτήσεις call και apply). Αυτό που κάνει η bind είναι να πάρει μια οποιαδήποτε συνάρτηση F και να σου επιστρέψει μία άλλη συνάρτηση G η οποία λειτουργεί ακριβώς όπως η F με μόνη διαφορά ότι κατά την εκτέλεση της G η τιμή του this είναι πάντα ίση με αυτό που πέρασες στην bind, ανεξάρτητα του πώς την κάλεσες. Ή με άλλα λόγια, η bind "πακετάρει" μια συνάρτηση με ένα this που θα της υποδείξεις "μια για πάντα". Οπότε τώρα έχεις: var getValue = obj.getValue; getValue(); // undefined var boundGetValue = getValue.bind(obj); // αυτό που λέγαμε boundGetValue(); // 42 επειδή το this είναι πάλι obj 2
slevinkelevra Δημοσ. 1 Απριλίου 2014 Μέλος Δημοσ. 1 Απριλίου 2014 Αχα! ΟΚ defacer ευχαριστώ πολύ για το χρόνο σου. Makes sense now. Αλλά ρε φίλε, σόρρυ κ πάλι, άμα θέλω η getValue να μου δίνει συνεχώς 42 μπορώ να την καλώ ως obj.getValue(); και άμα θέλω να δίνει το global object την αποθηκεύω σε άλλο var ή μπορεί κάθε object να έχει τη δικιά του getValue και να δίνει το τοπικό value. ΟΚ, πρακτικό είναι το θέμα μου τώρα. Που μπορέι να χρησιμεύσει η bind, αφού υπάρχουν απλούστερες εναλλακτικές?
defacer Δημοσ. 1 Απριλίου 2014 Δημοσ. 1 Απριλίου 2014 Έχεις καταλάβει ότι το this που εμφανίζεται μέσα σε μια function είναι "άσχετο" με το αντικείμενο στο οποίο τυχαίνει να είναι ορισμένη αυτή η function. Το επόμενο βήμα είναι να σκεφτείς ότι περνάμε functions σαν τιμές δεξιά κι αριστερά όλη την ώρα (οπότε αποδεσμεύονται από οποιοδήποτε this), αλλά σε πολλές περιπτώσεις που το κάνουμε αυτό μας ενδιαφέρει πολύ η τιμή του this όταν τελικά κληθεί η συνάρτηση. Σκέψου ότι σ' αυτή την περίπτωση: var f1 = "foo".indexOf; var f2 = string.prototype.indexOf; οι f1 και f2 είναι ακριβώς η ίδια συνάρτηση με την ίδια συμπεριφορά. Είτε κάνεις f1("f") είτε f2("f") το ίδιο αποτέλεσμα θα πάρεις (-1), το οποίο ίσως δεν είναι αυτό που περίμενες. Πρακτικό παράδειγμα τώρα. Θες να φιλτράρεις ένα πίνακα από string ούτως ώστε να μείνουν μόνο αυτά που κάνουν match κάποιο συγκεκριμένο regular expression. Οπότε έχεις var re = /foo/; var strings = ["foo", "bar"]; και θα χρησιμοποιήσεις την array.prototype.filter για να κάνεις τη δουλειά. Πώς θα το κάνεις;
slevinkelevra Δημοσ. 1 Απριλίου 2014 Μέλος Δημοσ. 1 Απριλίου 2014 Καταρχάς ευχαριστώ που ασχολείσαι.Λίγη υπομομή γιατί εχω μπερδευτεί. Δυστυχώς η μονη μου σοβαρή ενασχόληση με js ειναι τα Openlayers που εμαθα καποια πραγματα τρεχωντας για να βγει ενα project. Γι αυτο εχω κενα που προσπαθω να καλυψω. Στην ερωτηση σου τωρα. Αρχικά μπορώ να κάνω αυτό var strings = ["foo", "bar"]; function defacerFilter (elem){ return elem =="foo"; } alert (strings.filter(defacerFilter)); και να κανει alert foo με τη χρήση bind μπορω να κάνω var strings = ["foo", "bar"]; function defacerFilter (elem){ return elem ==this; } var slevin = defacerFilter.bind("foo"); alert (strings.filter(slevin)); και παλι να κανει alert foo. Οποτε κανω χρηση οσων bind θελω για να φτιαξω standard φιλτρα με σταθερα this? Βεβαια και παλι θα μπορουσα να μη χρησιμοποιησω bind και απλα να φτιαξω διαφορετικα φιλτρα με διαφορετικα κριτηρια. Σορρυ ρε φιλε, δε σου ζηταω τα ρεστα για τη js. Διορθωσε με οπου κανω λαθος.
defacer Δημοσ. 1 Απριλίου 2014 Δημοσ. 1 Απριλίου 2014 Αρχικά μπορώ να κάνω αυτό Δεν ήθελα αυτό. Ήθελα με RegExp.exec για να έχεις έτοιμη τη function και να μη χρειάζεται ντε και καλά να γράψεις την defacerFilter. Βασικά δηλαδή ήθελα αυτό: strings.filter(re.exec); το οποίο δε θα δουλέψει. Και ο λόγος που δε θα δουλέψει είναι ότι η RegExp.prototype.exec προφανώς για να ελέγξει αν κάνει match κάποιο string κάπου χρησιμοποιεί το this, το οποίο στην παραπάνω εκδοχή είναι το window. Θα μπορούσες τώρα να γράψεις strings.filter(function(str) { return re.exec(str); }); όπου κατά τα προηγούμενα επειδή γράφεις re.exec() το this παίρνει την τιμή re. Ε αντί να κάνεις αυτό μπορείς ισοδύναμα να κάνεις strings.filter(re.exec.bind(re)); Το γενικό νόημα από τα παραπάνω είναι ότι πάρα πολύ συχνά περνάς μια ξερή function κάπου ως callback. Όταν αυτή η function κληθεί τότε εκτός κι αν έχουν ληφθεί συγκεκριμένα μέτρα, επειδή την πέρασες όχι μαζί με "το αντικείμενο στο οποίο ανήκει" (ας πούμε) αλλά ξερή, το this θα είναι window πράγμα που πολλές φορές δε μας κάνει. Οπότε χρησιμοποιείς είτε την bind πριν περάσεις κάπου το callback για να κλειδώσει η τιμή του this όπως έκανα παραπάνω, είτε μια εκ των call/apply αφότου το περάσεις για να κανονιστεί την ώρα της κλήσης. Στην τελευταία περίπτωση εννοείται ότι θα πρέπει μαζί με το callback να περάσεις και την τιμή του this που θέλεις σα ξεχωριστό όρισμα, και ο κώδικας που παίρνει το callback θα πρέπει να φροντίσει αυτός να γίνει σωστά το call/apply. Στην πραγματικότητα η array.prototype.filter υποστηρίζει αυτόν τον τρόπο χρήσης παίρνοντας δεύτερο όρισμα: strings.filter(re.exec, re); οπότε αν θες ρίξε και μια ματιά στο documentation για να δεις τι κάνει μ' αυτό το δεύτερο όρισμα (στην ενότητα "polyfill" υπάρχει υλοποίηση σε JavaScript) και πιστεύω είσαι κομπλέ. 1
slevinkelevra Δημοσ. 1 Απριλίου 2014 Μέλος Δημοσ. 1 Απριλίου 2014 Ναι, οκ έγινε. Μια χαρά τώρα. Ολ δε πισες ιν δε ραιτ ποζισιονς. Ευχαριστώ πολύ φίλος!!!
Προτεινόμενες αναρτήσεις
Δημιουργήστε ένα λογαριασμό ή συνδεθείτε για να σχολιάσετε
Πρέπει να είστε μέλος για να αφήσετε σχόλιο
Δημιουργία λογαριασμού
Εγγραφείτε με νέο λογαριασμό στην κοινότητα μας. Είναι πανεύκολο!
Δημιουργία νέου λογαριασμούΣύνδεση
Έχετε ήδη λογαριασμό; Συνδεθείτε εδώ.
Συνδεθείτε τώρα