Προς το περιεχόμενο

Προτεινόμενες αναρτήσεις

Δημοσ.

Καλησπέρα και πάλι.

Έχω ξαναπιάσει 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...ειδα Link.png Site: αυτό .Στο παραδειγμα που εχει στο "Creating a bound function" με το ποτε ειναι το Χ 9 και ποτε 81...

μου κανει παλι λιγο overkill για τους παραπανω λογους και επισης

δεν καταλαβαινω τη διαφορα module.getX() και module.getX. Βασικα δεν καταλαβαινω γιατι αυτο 

var getX = module.getX;
getX(); 

βγαζει 9.Πως κολλαει με το global x και βγαζει 9?

 

Το ξερω οτι ειναι φιλοσοφικο το θεμα αλλα δεν εχω ποιον αλλον να ρωτησω. Οποιος εχει ορεξη να μου εξηγησει , ευπροσδεκτος. 

 

Ευχαριστω πολυ

Δημοσ.

Πρώτα πρέπει να έχεις υπόψη πώς ακριβώς δουλεύει το 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
  • Like 2
Δημοσ.

Αχα! ΟΚ defacer ευχαριστώ πολύ για το χρόνο σου. Makes sense now. Αλλά ρε φίλε, σόρρυ κ πάλι, άμα θέλω η getValue να μου δίνει συνεχώς 42 μπορώ να την καλώ ως 

obj.getValue(); 

και άμα θέλω να δίνει το global object την αποθηκεύω σε άλλο var ή μπορεί κάθε object να έχει τη δικιά του getValue και να δίνει το τοπικό value. ΟΚ, πρακτικό είναι το θέμα μου τώρα. Που μπορέι να χρησιμεύσει η bind, αφού υπάρχουν απλούστερες εναλλακτικές? 

Δημοσ.

Έχεις καταλάβει ότι το 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 για να κάνεις τη δουλειά. Πώς θα το κάνεις;

Δημοσ.

Καταρχάς ευχαριστώ που ασχολείσαι.Λίγη υπομομή γιατί εχω μπερδευτεί. Δυστυχώς η μονη μου σοβαρή ενασχόληση με 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. Διορθωσε με οπου κανω λαθος.

Δημοσ.
Αρχικά μπορώ να κάνω αυτό
 
Δεν ήθελα αυτό. Ήθελα με 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) και πιστεύω είσαι κομπλέ.

  • Like 1

Δημιουργήστε ένα λογαριασμό ή συνδεθείτε για να σχολιάσετε

Πρέπει να είστε μέλος για να αφήσετε σχόλιο

Δημιουργία λογαριασμού

Εγγραφείτε με νέο λογαριασμό στην κοινότητα μας. Είναι πανεύκολο!

Δημιουργία νέου λογαριασμού

Σύνδεση

Έχετε ήδη λογαριασμό; Συνδεθείτε εδώ.

Συνδεθείτε τώρα
  • Δημιουργία νέου...