Jump to content
Slate Blackcurrant Watermelon Strawberry Orange Banana Apple Emerald Chocolate Marble
Slate Blackcurrant Watermelon Strawberry Orange Banana Apple Emerald Chocolate Marble
Sign in to follow this  
Anastasis

Εισαγωγή στη σύγχρονη JavaScript

Recommended Posts

javascriptlogo-1.jpg

Γιατί χρειάζεται μια νέα εισαγωγή; Διότι η JavaScript μπορεί δίκαια να ισχυριστεί ότι είναι η πιο παρεξηγημένη γλώσσα του κόσμου. Αν και συχνά γίνεται αντικείμενο χλευασμού και χαρακτηρίζεται ως παιχνίδι, πίσω από την απατηλή της απλότητα κρύβονται μερικά ισχυρά γλωσσικά στοιχεία. Ο χρόνος που πέρασε είδε να ξεφυτρώνουν ένας αριθμός από εφαρμογές JavaScript μεγάλης εμβέλειας, δείχνοντας ότι η βαθύτερη γνώση αυτής της τεχνολογίας είναι ένα σημαντικό προσόν για κάθε web developer.

Είναι χρήσιμο να αρχίσουμε με μια ιδέα από την ιστορία της γλώσσας. Η JavaScript δημιουργήθηκε το 1995 από τον Brendan Eich, έναν μηχανικό της Netscape, και εκδόθηκε με τον Netscape 2 στις αρχές του 1996. Το αρχικό της όνομα ήταν LiveScript, αλλά μια ατυχής απόφαση μάρκετινγκ την μετονόμασε σε JavaScript. Το σκεπτικό ήταν να κεφαλαιοποιηθεί η δημοτικότητα της γλώσσας Java της Sun, παρότι οι δύο γλώσσες έχουν ελάχιστα κοινά στοιχεία μεταξύ τους. Αυτό αποτελεί μόνιμη πηγή σύγχυσης από τότε μέχρι σήμερα.

Μερικούς μήνες αργότερα η Microsoft παρουσίασε μια σε γενικές γραμμές συμβατή έκδοση της γλώσσας με το όνομα JScript (μαζί με τον IE3). Η Netscape υπέβαλλε τη γλώσσα στον ECMA International, έναν Ευρωπαϊκό οργανισμό προτύπων, μια πρωτοβουλία που κατέληξε στην πρώτη έκδοση της EcmaScript το 1997. Το πρότυπο έφτασε στην έκδοση 3 το 1999 και από τότε παρέμεινε γενικά αμετάβλητο, αν και η έκδοση 4 βρίσκεται σε φάση ανάπτυξης.

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

Αντίθετα από τις περισσότερες γλώσσες προγραμματισμού η γλώσσα JavaScript δεν έρχεται εφοδιασμένη με δυνατότητες εισόδου/εξόδου. Είναι σχεδιασμένη ως γλώσσα scripting σε ένα περιβάλλον που τη φιλοξενεί, και η ύπαρξη μηχανισμών επικοινωνίας με τον έξω κόσμο είναι ευθύνη αυτού του περιβάλλοντος. Το πιο συνηθισμένο περιβάλλον φιλοξενίας είναι ο browser, αλλά interpreters JavaScript μπορούν να βρεθούν στον Acrobat της Adobe, το Photoshop, τη μηχανή Widget της Yahoo! και αλλού.


Γενική Εικόνα

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

- Numbers
- Strings
- Booleans
- Functions
- Objects

...α, και Undefined και Null, που είναι κάπως παράξενοι τύποι. Και Arrays, που είναι ειδικού τύπου αντικείμενα. Και Dates και Regular Expressions που είναι αντικείμενα που παίρνετε δωρεάν. Και για να είμαι τεχνικά ακριβής οι functions δεν είναι παρά ειδικού τύπου αντικείμενα. Επομένως το διάγραμμα των τύπων μοιάζει περισσότερο με αυτό:

- Number
- String
- Boolean
- Object
--- Function
--- Array
--- Date
--- RegExp
- Null
- Undefined

Και υπάρχει επίσης κι ένας ενσωματωμένος τύπος Error. Ωστόσο τα πράγματα είναι πολύ ευκολότερα αν παραμείνουμε στο πρώτο διάγραμμα.


Αριθμοί

Οι αριθμοί στη JavaScript είναι «τιμές διπλής-ακρίβειας 64-bit μορφής IEEE 754», σύμφωνα με τις προδιαγραφές. Αυτό έχει μερικές ενδιαφέρουσες συνέπειες. Δεν υπάρχουν ακέραιοι στη JavaScript, επομένως πρέπει να είστε λίγο προσεκτικοί με την αριθμητική σας αν έχετε συνηθίσει τα μαθηματικά της Java ή της C. Να είστε σε εγρήγορση για καταστάσεις σαν:


 

κώδικας:
0.1 + 0.2 = 0.30000000000000004



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

κώδικας:
Math.sin(3.5);
d = Math.PI * r * r;



Μπορείτε να μετατρέψετε έναν αριθμό χρησιμοποιώντας την ενσωματωμένη συνάρτηση parseInt(). Αυτή δέχεται την αριθμητική βάση της μετατροπής ως προαιρετικό δεύτερο όρισμα, το οποίο θα πρέπει να παρέχετε πάντα:
 

κώδικας:
> parseInt("123")
123
> parseInt("010")
8



Αυτό συνέβη γιατί η συνάρτηση parseInt αποφάσισε να χειριστεί το string σαν οκταδικό αριθμό λόγω του αρχικού ψηφίου 0. Αν φροντίσετε να ορίζετε πάντα τη βάση μπορείτε να αποφύγετε εντελώς αυτό το πρόβλημα:
 

κώδικας:
> parseInt("123", 10)
123
> parseInt("010", 10)
10



Αν θέλετε να μετατρέψετε ένα δυαδικό αριθμό σε δεκαδικό απλά αλλάξτε τη βάση:
 

κώδικας:
> parseInt("11", 2)
3



Η JavaScript έχει επίσης μία ειδική τιμή που λέγεται Not-a-Number. Αυτή κάνει την εμφάνισή της όταν προσπαθήσετε να κάνετε πράγματα όπως να μετατρέψετε μια μη-αριθμητική τιμή σε αριθμό.
 

κώδικας:
> parseInt("hello", 10)
NaN



Η τιμή NaN είναι τοξική. Αν τη δώσετε ως είσοδο σε οποιαδήποτε αριθμητική πράξη το αποτέλεσμα θα είναι επίσης NaN:
 

κώδικας:
> NaN + 5
NaN



Μπορείτε να την ανιχνεύσετε χρησιμοποιώντας την ενσωματωμένη συνάρτηση isNaN:
 

κώδικας:
> isNaN(NaN)
true



Η JavaScript έχει επίσης ειδικές τιμές για το θετικό και αρνητικό άπειρο.
 

κώδικας:
> 1 / 0
Infinity
> -1 / 0
-Infinity




Strings

Τα strings στη JavaScript είναι ακολουθίες χαρακτήρων. Για την ακρίβεια είναι ακολουθίες χαρακτήρων unicode, με κάθε χαρακτήρα να αντιστοιχεί σε ένα αριθμό 16 bit. Αυτό θα πρέπει να ακούγεται ευχάριστα στα αυτιά οποιουδήποτε ασχολήθηκε ποτέ με internationalization.

Όταν χρειάζεστε ένα μεμονωμένο χαρακτήρα απλά χρησιμοποιείστε ένα string με μήκος 1.

Για να βρείτε το μήκος ενός string, χρησιμοποιείστε την ιδιότητα length.

 

κώδικας:
> "hello".length
5



Να η πρώτη μας επαφή με τα αντικείμενα JavaScript! Αλήθεια, ανέφερα ότι και τα strings είναι αντικείμενα; Έχουν και μεθόδους:
 

κώδικας:
> "hello".charAt(0)
h
> "hello, world".replace("hello", "goodbye")
goodbye, world
> "hello".toUpperCase()
HELLO




Άλλοι τύποι

Το null σημαίνει μία εσκεμμένη μη-τιμή. Το undefined σημαίνει ότι δεν έχει ακόμα αποδοθεί κάποια τιμή. Θα μιλήσουμε για τις μεταβλητές αργότερα, αλλά στη JavaScript είναι δυνατό να ορίσουμε μια μεταβλητή χωρίς να της δώσουμε τιμή. Αν το κάνουμε αυτό η τιμή της μεταβλητής είναι η τιμή «undefined».

Η JavaScript έχει ένα τύπο boolean, ο οποίος είναι είτε true είτε false (και τα δύο είναι keywords). Οτιδήποτε άλλο στη γλώσσα θεωρείται είτε αληθές είτε ψευδές, το οποίο προσδιορίζει τι συμβαίνει όταν χρησιμοποιηθεί σε θέση boolean. Οι κανόνες περί αλήθειας και ψεύδους είναι οι εξής:

0, "", NaN, null, και undefined είναι ψευδή. Οτιδήποτε άλλο είναι αληθές.

Υποστηρίζονται τελεστές boolean όπως &&, || και !. Μπορείτε να μετατρέψετε κάθε τιμή σε boolean εφαρμόζοντας δύο φορές τον τελεστή άρνησης:

 

κώδικας:
> !!""
false
> !!234
true




Μεταβλητές

Οι μεταβλητές στη JavaScript δηλώνονται με τη χρήση του keyword var:

 

κώδικας:
var a;
var name = "simon";



Αν δηλώσετε μια μεταβλητή χωρίς να της αποδώσετε κάτι, η τιμή της είναι undefined.


Τελεστές

Οι αριθμητικοί τελεστές της JavaScript είναι οι +, -, *, / και %, το οποίο είναι το υπόλοιπο ακέραιας διαίρεσης. Οι τιμές αποδίδονται με =, και υπάρχουν επίσης σύνθετες εντολές απόδοσης όπως += και -= οι οποίες αναλύονται σε x = x τελεστής y.

 

κώδικας:
x += 5
x = x + 5



Μπορείτε να χρησιμοποιήσετε τους ++ και -- για άυξηση και μείωση αντίστοιχα. Αυτοί μπορούν να τοποθετηθούν πριν ή μετά τη μεταβλητή (prefix/postfix operators).

Ο τελεστής + κάνει επιπλέον και συνένωση string:

 

κώδικας:
> "hello" + " world"
hello world



Αν προσθέσετε έναν αριθμό κι ένα string (ή άλλη τιμή) τα πάντα μετατρέπονται σε string πριν την πράξη. Αυτό μπορεί να σας συλλάβει εξ απροόπτου:
 

κώδικας:
> "3" + 4 + 5
345
> 3 + 4 + "5"
75



Ένας χρήσιμος τρόπος να μετατρέψετε κάτι σε string είναι να του προσθέσετε το κενό string.

Οι συγκρίσεις στη JavaScript μπορούν να γίνουν με χρήση των <, >, <= και >=. Αυτοί λειτουργούν εξίσου με strings και αριθμούς. Η ισότητα είναι ελαφρά πιο περίπλοκη. Ο τελεστής == πραγματοποιεί μετατροπή τύπου αν του δώσετε διαφορετικούς τύπους, με ενίοτε ενδιαφέροντα αποτελέσματα:

 

κώδικας:
> "dog" == "dog"
true
> 1 == true
true



Αν αυτές οι μετατροπές είναι ανεπιθύμητες χρησιμοποιήστε τον τελεστή τριπλό-ίσον:
 

κώδικας:
> 1 === true
false
> true === true
true



Υπάρχουν επίσης τελεστές != και !==.

Η JavaScript έχει ακόμα και δυαδικούς τελεστές. Αν ποτέ τους επιθυμήσετε, εκεί είναι.


Δομές Ελέγχου

Η JavaScript έχει ένα παραπλήσιο πακέτο δομών ελέγχου με άλλες γλώσσες της οικογένειας C. Οι εκτέλεση εντολών κατά συνθήκη υποστηρίζεται με τα if και else. Μπορείτε να σχηματίσετε αλυσίδες απ' αυτά αν θέλετε:

 

κώδικας:
var name = "kittens";
if (name == "puppies") {
  name += "!";
} else if (name == "kittens") {
  name += "!!";
} else {
  name = "!" + name;
}
name == "kittens!!"



Η JavaScript έχει βρόγχους while και do-while. Ο δεύτερος είναι καλός όταν θέλουμε να είμαστε σίγουροι πως το σώμα του βρόγχου θα εκτελεστεί τουλάχιστον μία φορά:
 

κώδικας:
while (true) {
  // an infinite loop!
}

do {
  var input = get_input();
} while (inputIsNotValid(input))



Ο βρόγχος for της JavaScript είναι ο ίδιος όπως στη C και τη Java, σας επιτρέπει να ορίσετε όλα τα δεδομένα ελέγχου του βρόγχου σε μία μόνο γραμμή.
 

κώδικας:
for (var i = 0; i < 5; i++) {
  // Will execute 5 times
}



Οι τελεστές && και || χρησιμοποιούν λογική παράκαμψης (short-circuit), το οποίο σημαίνει ότι η εκτέλεση του δεύτερου τελεστέου θα εξαρτηθεί από τον πρώτο. Αυτό είναι χρήσιμο για τον έλεγχο του null πριν την προσπέλαση ιδιοτήτων αντικειμένων.
 

κώδικας:
var name = o && o.getName();



Ή για τον καθορισμό προεπιλεγμένων τιμών:
 

κώδικας:
var name = otherName || "default";



Η JavaScript έχει ένα τριπλό τελεστή για κατά συνθήκη εντολές της μίας γραμμής:
 

κώδικας:
var allowed = (age > 18) ? "yes" : "no";



Η εντολή switch μπορεί να χρησιμοποιηθεί για πολλαπλές διακλαδώσεις με βάση έναν αριθμό ή string:
 

κώδικας:
switch(action) {
    case 'draw':
        drawit();
        break;
    case 'eat':
        eatit();
        break;
    default:
        donothing();
}



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

κώδικας:
switch(a) {
    case 1: // fallthrough
    case 2:
        eatit();
        break;
    default:
        donothing();
}



Ο όρος default είναι προαιρετικός. Μπορείτε να έχετε εκφράσεις τόσο στο switch όσο και στα cases αν θέλετε. Οι συγκρίσεις μεταξύ των δύο γίνονται με τον τελεστή === (αυστηρή ισότητα):
 

κώδικας:
switch(1 + 3):
    case 2 + 2:
        yay();
        break;
    default:
        neverhappens();
}




Αντικείμενα

Τα αντικείμενα της JavaScript είναι απλά συλλογές από ζευγάρια Όνομα/Τιμή. Σαν τέτοια είναι παρεμφερή με:

- Dictionaries στην Python
- Hashes στις Perl και Ruby
- Hash tables στις C και C++
- HashMaps στη Java
- Associative arrays στην PHP

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

Το τμήμα «Όνομα» είναι ένα string, ενώ το τμήμα «Τιμή» μπορεί να είναι κάθε τιμή JavaScript, συμπεριλαμβανομένων άλλων αντικειμένων. Αυτό σας επιτρέπει να χτίζετε δομές δεδομένων οποιουδήποτε βαθμού πολυπλοκότητας.

Υπάρχουν δύο βασικοί τρόποι να δημιουργηθεί ένα αντικείμενο:

 

κώδικας:
var obj = new Object();



Και:
 

κώδικας:
var obj = {};



Αυτοί είναι σημασιολογικά ισοδύναμοι. Ο δεύτερος ονομάζεται σύνταξη literal και είναι πιο βολικός. Η σύνταξη literal δεν υπήρχε στις πολύ πρώιμες εκδόσεις της γλώσσας, και αυτός είναι ο λόγος που βλέπετε τόσο πολύ κώδικα να χρησιμοποιεί την παλιά μέθοδο.

Άπαξ και δημιουργήθηκε, οι ιδιότητες του αντικειμένου μπορούν να προσπελαστούν πάλι με δύο τρόπους:

 

κώδικας:
obj.name = "Simon"
var name = obj.name;



Και...
 

κώδικας:
obj["name"] = "Simon";
var name = obj["name"];



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

κώδικας:
obj.for = "Simon"; // Συντακτικό σφάλμα
obj["for"] = "Simon"; // Δουλεύει θαυμάσια



Η σύνταξη literal μπορεί να χρησιμοποιηθεί για να αρχικοποιήσει ένα αντικείμενο στην ολότητά του:
 

κώδικας:
var obj = {
    name: "Carrot",
    "for": "Max",
    details: {
        color: "orange",
        size: 12
    }
}



Είναι δυνατή η δημιουργία αλυσίδων από προσπελάσεις ιδιοτήτων:
 

κώδικας:
> obj.details.color
orange
> obj["details"]["size"]
12




Arrays

Τα Arrays στη JavaScript είναι απλά ένα ειδικός τύπος αντικειμένου, όπου ως ονόματα ιδιοτήτων αντί για strings γίνετε χρήση αριθμών. Λειτουργούν σε μεγάλο βαθμό ως κανονικά αντικείμενα (που προσπελαύνονται πάντα με τη σύνταξη []) αλλά έχουν μία μαγική ιδιότητα με όνομα length. Αυτή είναι πάντα κατά μια μονάδα μεγαλύτερη από το μεγαλύτερο δείκτη του array.

Ο παλιός τρόπος δημιουργίας arrays έχει ως εξής:

 

κώδικας:
> var a = new Array();
> a[0] = "dog";
> a[1] = "cat";
> a[2] = "hen";
> a.length
3



Μια πιο βολική σύνταξη είναι τα array literals:
 

κώδικας:
> var a = ["dog", "cat", "hen"];
> a.length
3



Το να αφήσετε ένα πλεονάζον κόμμα στο τέλος του array literal ερμηνεύεται διαφορετικά από browser σε browser, γι αυτό μην το κάνετε.

Σημειώστε πως η array.length δεν είναι πάντα ο αριθμός στοιχείων του array. Δείτε το παρακάτω:

 

κώδικας:
> var a = ["dog", "cat", "hen"];
> a[100] = "fox";
> a.length
101



Θυμηθείτε, το length του array είναι μια μονάδα παραπάνω από το μεγαλύτερο δείκτη.

Αν ζητήσετε έναν μη-υπαρκτό δείκτη array, θα πάρετε undefined:

 

κώδικας:
> typeof(a[90])]
undefined



Λαμβάνοντας υπόψη τα παραπάνω, μπορείτε να διατρέξετε ένα array χρησιμοποιώντας το εξής:
 

κώδικας:
for (var i = 0; i < a.length; i++) {
    // Do something with a
}



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

κώδικας:

for (var i = 0, j = a.length; i < j; i++) {
    // Do something with a
}



Ένα ακόμα ωραιότερο ιδίωμα είναι:
 

κώδικας:

for (var i = 0, item; item = a; i++) {
    // Do something with item
}



Εδώ θέτουμε δύο μεταβλητές. Στο μέσο της εντολής for συμβαίνει μια απόδοση τιμής και ταυτόχρονα ένας έλεγχος αλήθειας. Αν η απόδοση επιτύχει, ο βρόγχος συνεχίζει. Εφόσον το i αυξάνεται κάθε φορά, τα περιεχόμενα του array θα αποδοθούν στο item το ένα μετά το άλλο. Ο βρόγχος τερματίζει όταν βρεθεί ένα ψευδές στοιχείο (όπως είναι το undefined).

Σημειώστε πως αυτό το trick θα πρέπει να χρησιμοποιείται μόνο για arrays που γνωρίζετε ότι δεν περιέχουν ψευδείς τιμές (για παράδειγμα arrays αντικειμένων ή κόμβων DOM). Αν διατρέχετε αριθμητικά δεδομένα που μπορεί να περιλαμβάνουν το 0 ή strings που μπορεί να περιλαμβάνουν το κενό string, χρησιμοποιήστε το ιδίωμα i, j.

Αν θέλετε να προσθέσετε ένα στοιχείο σε ένα array, ο ασφαλέστερος τρόπος είναι αυτός:
 

κώδικας:

a[a.length] = item;



Καθώς η a.length είναι μια μονάδα μεγαλύτερη από τον μεγαλύτερο δείκτη, μπορείτε να είστε σίγουροι ότι κάνετε απόδοση σε μία κενή θέση στο τέλος του array.

Τα arrays έρχονται εφοδιασμένα μα αρκετές μεθόδους:

a.toString(), a.toLocaleString(), a.concat(item, ..), a.join(sep),
a.pop(), a.push(item, ..), a.reverse(), a.shift(), a.slice(start, end),
a.sort(cmpfn), a.splice(start, delcount, [item]..), a.unshift([item]..)

- η concat επιστρέφει ένα νέο array που περιέχει και τα στοιχεία που προστέθηκαν.
- η pop αφαιρεί και επιστρέφει το τελευταίο στοιχείο.
- η push προσθέτει ένα ή περισσότερα στοιχεία στο τέλος (όπως το ιδίωμα ar[ar.length]).
- η slice επιστρέφει ένα τμήμα του array.
- η sort ταξινομεί και δέχεται ως προαιρετικό όρισμα μία συνάρτηση για τις συγκρίσεις.
- η splice μεταβάλλει ένα array διαγράφοντας ένα τμήμα και αντικαθιστώντας το με άλλα στοιχεία.
- η unshift προσθέτει στοιχεία στην αρχή του array.


Συναρτήσεις

Μαζί με τα αντικείμενα, οι συναρτήσεις είναι το βασικό συστατικό στην κατανόηση της JavaScript. Η πιο στοιχειώδης συνάρτηση δε θα μπορούσε να είναι πολύ απλούστερη απ' αυτήν εδώ:
 

κώδικας:

function add(x, y) {
    var total = x + y;
    return total;
}



Αυτή περιγράφει οτιδήποτε υπάρχει για να μάθει κανείς σχετικά με τις βασικές συναρτήσεις. Μια συνάρτηση JavaScript μπορεί να λάβει 0 ή περισσότερες επώνυμες παραμέτρους. Το σώμα της μπορεί να περιέχει όσες εντολές θέλετε, και μπορείτε να ορίσετε τις δικές τις μεταβλητές οι οποίες είναι τοπικές σε αυτή τη συνάρτηση. Η εντολή return μπορεί να χρησιμοποιηθεί ανά πάσα στιγμή για την επιστροφή μίας τιμής, τερματίζοντας τη συνάρτηση. Αν δε χρησιμοποιηθεί εντολή return (ή χρησιμοποιηθεί χωρίς τιμή), η JavaScript επιστρέφει undefined.

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

κώδικας:

> add()
Nan // Δε μπορείτε να κάνετε πρόσθεση με το undefined



Μπορείτε ακόμα να περάσετε περισσότερα ορίσματα απ' όσα περιμένει η συνάρτηση:
 

κώδικας:

> add(2, 3, 4)
5 // προστέθηκαν τα πρώτα δύο, το 4 αγνοήθηκε.



Αυτό ίσως μοιάζει λίγο χαζό, αλλά οι συναρτήσεις έχουν πρόσβαση σε μια επιπλέον μεταβλητή μέσα στο σώμα τους που λέγετε arguments, η οποία είναι ένα αντικείμενο σαν array που κρατά όλες τις τιμές που περάστηκαν στη συνάρτηση. Ας ξαναγράψουμε τη συνάρτηση add έτσι ώστε να μπορεί να δεχτεί κάθε αριθμό ορισμάτων:
 

κώδικας:

function add() {
    var sum = 0;
    for (var i = 0, j = arguments.length; i < j; i++) {
        sum += arguments;
    }
    return sum;
}

> add(2, 3, 4, 5)
14



Αυτή ωστόσο δεν είναι περισσότερο χρήσιμη απ' το να γράφαμε 2 + 3 + 4 + 5. Ας φτιάξουμε μία συνάρτηση για τον υπολογισμό του μέσου όρου:
 

κώδικας:

function avg() {
    var sum = 0;
    for (var i = 0, j = arguments.length; i < j; i++) {
        sum += arguments;
    }
    return sum / arguments.length;
}
> avg(2, 3, 4, 5)
3.5



Αυτή είναι αρκετά χρήσιμη, αλλά εγκαινιάζει ένα νέο πρόβλημα. Η συνάρτηση avg() δέχεται μία λίστα ορισμάτων χωρισμένη με κόμμα, αλλά τι θα κάνατε αν θέλατε το μέσο όρο ενός array; Θα μπορούσατε απλά να ξαναγράψετε τη συνάρτηση ως εξής:
 

κώδικας:

function avgArray(arr) {
    var sum = 0;
    for (var i = 0, j = arr.length; i < j; i++) {
        sum += arr;
    }
    return sum / arr.length;
}
> avgArray([2, 3, 4, 5])
3.5



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

κώδικας:

> avg.apply(null, [2, 3, 4, 5])
3.5



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

Η JavaScript σας επιτρέπει να δημιουργήσετε ανώνυμες συναρτήσεις.
 

κώδικας:

var avg = function() {
    var sum = 0;
    for (var i = 0, j = arguments.length; i < j; i++) {
        sum += arguments;
    }
    return sum / arguments.length;
}



Αυτή η μορφή είναι σημασιολογικά ισοδύναμη με τη μορφή function avg(). Είναι εξαιρετικά ισχυρή, καθώς σας επιτρέπει να βάλετε μια πλήρη συνάρτηση εκεί που κανονικά θα βάζατε μία έκφραση. Αυτό επιτρέπει κάθε είδους έξυπνα τρικ. Να ένας τρόπος απόκρυψης μερικών τοπικών μεταβλητών, όπως το block scope στη C:
 

κώδικας:

> var a = 1;
> var b = 2;
> (function() {
    var b = 3;
    a += b;
})();
> a
4
> b
2



Η JavaScript σας επιτρέπει να κάνετε αναδρομική κλήση συναρτήσεων. Αυτό είναι ιδιαίτερα χρήσιμο όταν έχετε να κάνετε με δομές δέντρου, όπως αυτές που παίρνετε από το DOM των browsers.
 

κώδικας:

function countChars(elm) {
    if (elm.nodeType == 3) { // TEXT_NODE
        return elm.nodeValue.length;
    }
    var count = 0;
    for (var i = 0, child; child = elm.childNodes; i++) {
        count += countChars(child);
    }
    return count;
}



Αυτό αναδεικνύει ένα δυνητικό πρόβλημα με τις ανώνυμες συναρτήσεις: πώς μπορείτε να τις καλέσετε αναδρομικά αν δε γνωρίζετε το όνομά τους; Η απάντηση βρίσκεται στο αντικείμενο arguments, το οποίο εκτός από το να λειτουργεί ως λίστα ορισμάτων παρέχει επιπλέον μια ιδιότητα με όνομα arguments.callee. Αυτή αναφέρεται πάντα στην τρέχουσα συνάρτηση, και ιδού πως μπορεί με τη βοήθειά της να γίνει εφικτή η αναδρομική κλήση:
 

κώδικας:

var charsInBody = (function(elm) {
    if (elm.nodeType == 3) { // TEXT_NODE
        return elm.nodeValue.length;
    }
    var count = 0;
    for (var i = 0, child; child = elm.childNodes; i++) {
        count += arguments.callee(child);
    }
    return count;
})(document.body);



Εφόσον η arguments.callee είναι η τρέχουσα συνάρτηση και όλες οι συναρτήσεις είναι αντικείμενα, μπορείτε να χρησιμοποιήσετε την arguments.callee για να διατηρήσετε δεδομένα από τη μία κλήση της συνάρτησης στην επόμενη. Να μια συνάρτηση που θυμάται πόσες φορές έχει κληθεί:
 

κώδικας:

function counter() {
    if (!arguments.callee.count) {
        arguments.callee.count = 0;
    }
    return arguments.callee.count++;
}

> counter()
0
> counter()
1
> counter()
2




Μεθόδοι Αντικείμενων

Στον κλασικό αντικειμενοστραφή προγραμματισμό τα αντικείμενα είναι συλλογές δεδομένων και μεθόδων που ενεργούν πάνω σε αυτά τα δεδομένα. Ας θεωρήσουμε ένα αντικείμενο person με πεδία μικρό όνομα κι επώνυμο. Υπάρχουν δύο τρόποι εμφάνισης του πλήρους ονόματος: ως «first last» ή ως «last, first». Να ένας τρόπος να γίνει αυτό χρησιμοποιώντας τις συναρτήσεις και τα αντικείμενα που συζητήσαμε προηγουμένως:
 

κώδικας:

function makePerson(first, last) {
    return {
        first: first,
        last: last
    }
}
function personFullName(person) {
    return person.first + ' ' + person.last;
}
function personFullNameReversed(person) {
    return person.last + ', ' + person.first
}
> s = makePerson("Simon", "Willison");
> personFullName(s)
Simon Willison
> personFullNameReversed(s)
Willison, Simon



Αυτό λειτουργεί, αλλά δεν είναι πολύ όμορφο. Θα καταλήξετε με ντουζίνες συναρτήσεων στο global namespace. Αυτό που θέλουμε στ' αλήθεια είναι ένας τρόπος να προσδέσουμε μια συνάρτηση σε ένα αντικείμενο. Μιας και οι συναρτήσεις είναι αντικείμενα, αυτό είναι εύκολο:
 

κώδικας:

function makePerson(first, last) {
    return {
        first: first,
        last: last,
        fullName: function() {
            return this.first + ' ' + this.last;
        },
        fullNameReversed: function() {
            return this.last + ', ' + this.first;
        }
    }
}
> s = makePerson("Simon", "Willison")
> s.fullName()
Simon Willison
> s.fullNameReversed()
Willison, Simon



Υπάρχει εδώ κάτι που συναντάμε για πρώτη φορά: το keyword this. Όταν χρησιμοποιείται μέσα σε μια συνάρτηση το this αναφέρεται στο τρέχον αντικείμενο. Το τι σημαίνει αυτό εξαρτάται από τον τρόπο που καλέσατε τη συνάρτηση. Αν την καλέσατε με χρήση της τελείας σε ένα αντικείμενο, αυτό το αντικείμενο γίνεται το this. Αν η κλήση έγινε χωρίς τη σύνταξη τελεία, το this αναφέρετε στο global object. Αυτή είναι μια συνηθισμένη πηγή σφαλμάτων. Για παράδειγμα:
 

κώδικας:

> s = makePerson("Simon", "Willison")
> var fullName = s.fullName;
> fullName()
undefined undefined



Όταν καλέσαμε fullName() το this αναφέρθηκε στο global object. Καθώς δεν υπάρχουν global μεταβλητές first και last πήραμε undefined για την κάθε μια απ' αυτές.

Μπορούμε να εκμεταλλευτούμε το keyword this για να βελτιώσουμε τη συνάρτηση makePerson:
 

κώδικας:

function Person(first, last) {
    this.first = first;
    this.last = last;
    this.fullName = function() {
        return this.first + ' ' + this.last;
    }
    this.fullNameReversed = function() {
        return this.last + ', ' + this.first;
    }
}
var s = new Person("Simon", "Willison");



Εγκαινιάσαμε άλλο ένα keyword: το new. Το new συνδέεται στενά με το this. Αυτό που κάνει είναι να δημιουργεί ένα ολοκαίνουργιο αντικείμενο, και μετά καλεί τη συνάρτηση και ταυτόχρονα κάνει το this να αναφέρεται σε αυτό το νέο αντικείμενο. Οι συναρτήσεις που σχεδιάστηκαν να καλούνται με το new ονομάζονται constructor functions. Είναι κοινή πρακτική να γράφουμε με κεφαλαίο πρώτο γράμμα αυτές τις συναρτήσεις, ως υπενθύμιση να τις καλέσουμε με το new.

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

κώδικας:

function personFullName() {
    return this.first + ' ' + this.last;
}
function personFullNameReversed() {
    return this.last + ', ' + this.first;
}
function Person(first, last) {
    this.first = first;
    this.last = last;
    this.fullName = personFullName;
    this.fullNameReversed = personFullNameReversed;
}



Αυτό είναι καλύτερο: δημιουργούμε τις μεθόδους-συναρτήσεις μόνο μια φορά, και αποδίδουμε αναφορές σε αυτές μέσα στον constructor. Μπορούμε να κάνουμε τίποτα καλύτερο απ' αυτό; Η απάντηση είναι ναι:
 

κώδικας:

function Person(first, last) {
    this.first = first;
    this.last = last;
}
Person.prototype.fullName = function() {
    return this.first + ' ' + this.last;
}
Person.prototype.fullNameReversed = function() {
    return this.last + ', ' + this.first;
}



Το Person.prototype είναι ένα αντικείμενο που το μοιράζονται όλα τα αντικείμενα Person. Αποτελεί μέρος της αλυσίδας αναζήτησης ιδιοτήτων: κάθε φορά που επιχειρούμε να προσπελάσουμε μια ιδιότητα του Person που δεν έχει οριστεί, η JavaScript θα ελέγξει το Person.prototype για να δει αν αυτή η ιδιότητα μπορεί να βρεθεί εκεί. Σαν αποτέλεσμα οτιδήποτε προστίθεται στο Person.prototype γίνεται διαθέσιμο σε όλα τα αντικείμενα που κατασκευάστηκαν με αυτόν τον constructor.

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

κώδικας:

> s = new Person("Simon", "Willison");
> s.firstNameCaps();
TypeError on line 1: s.firstNameCaps is not a function
> Person.prototype.firstNameCaps = function() {
    return this.first.toUpperCase()
}
> s.firstNameCaps()
SIMON



Είναι ενδιαφέρον ότι μπορείτε να προσθέσετε πράγματα στο prototype των ενσωματωμένων αντικειμένων της JavaScript. Ας προσθέσουμε μία μέθοδο στο String που να επιστρέφει αυτό το string αντεστραμμένο:
 

κώδικας:

> var s = "Simon";
> s.reversed()
TypeError on line 1: s.reversed is not a function
> String.prototype.reversed = function() {
    var r = '';
    for (var i = this.length - 1; i >= 0; i--) {
        r += this;
    }
    return r;
}
> s.reversed()
nomiS



Η νέα μας μέθοδος δουλεύει ακόμα και σε string literals!
 

κώδικας:

> "This can now be reversed".reversed()
desrever eb won nac sihT



Όπως ανέφερα προηγούμενα το prototype αποτελεί μέρος μιας αλυσίδας. Ο αρχικός κρίκος της αλυσίδας είναι το Object.prototype, του οποίου οι μέθοδοι περιλαμβάνουν το toString(). Αυτή είναι η μέθοδος που καλείται κάθε φορά που προσπαθείτε να μετατρέψετε ένα αντικείμενο σε string. Αυτό είναι χρήσιμο για το debugging του αντικειμένου μας:
 

κώδικας:

> var s = new Person("Simon", "Willison");
> s
[object Object]
> Person.prototype.toString = function() {
    return '<Person: ' + this.fullName() + '>';
}
> s
<Person: Simon Willison>



Θυμάστε ότι η avg.apply() είχε ένα null ως πρώτο όρισμα; Μπορούμε τώρα να το αναθεωρήσουμε. Το πρώτο όρισμα στην apply() είναι το αντικείμενο που θα πρέπει να γίνει το this. Για παράδειγμα να μια επιπόλαιη υλοποίηση του new:
 

κώδικας:

function trivialNew(constructor) {
    var o = {}; // Δημιουργία αντικειμένου
    constructor.apply(o, arguments);
    return o;
}



Αυτό δεν είναι ένα ακριβές υποκατάστατο του new γιατί παραλείπει τη σύνδεση με το κατάλληλο prototype. Είναι δύσκολο να βρεθούν καλά παραδείγματα για την επεξήγηση της apply(), και δεν είναι κάτι που χρησιμεύει πολύ συχνά, αλλά είναι χρήσιμο να ξέρετε γι αυτήν.

Η apply έχει μια αδελφή συνάρτηση με το όνομα call η οποία επίσης σας επιτρέπει να ορίζεται το this, αλλά αντί για ένα array δέχεται μια σειρά ορισμάτων.
 

κώδικας:

function lastNameCaps() {
    return this.last.toUpperCase();
}
var s = new Person("Simon", "Willison");
lastNameCaps.call(s);
// Είναι το ίδιο όπως:
s.lastNameCaps = lastNameCaps;
s.lastNameCaps();




Ένθετες Συναρτήσεις

Είναι επιτρεπτός ο ορισμός συναρτήσεων JavaScript μέσα σε άλλες συναρτήσεις. Το είδαμε προηγούμενα, σε μια συνάρτηση makePerson(). Μια σημαντική λεπτομέρεια των ένθετων συναρτήσεων είναι ότι έχουν πρόσβαση σε μεταβλητές στην εμβέλεια (scope) της εξωτερικής συνάρτησης:
 

κώδικας:

function betterExampleNeeded() {
    var a = 1;
    function oneMoreThanA() {
        return a + 1;
    }
    return oneMoreThanA();
}



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

Αυτό είναι επίσης σημαντικό αντίμετρο στο δέλεαρ των global μεταβλητών. Όταν γράφουμε πολύπλοκο κώδικα είναι συχνά δελεαστικό να κάνουμε χρήση global μεταβλητών για να μοιραστούμε κοινές τιμές σε πολλές συναρτήσεις - το οποίο οδηγεί σε κώδικα που είναι δύσκολος στη συντήρηση. Οι ένθετες συναρτήσεις μπορούν να μοιραστούν μεταβλητές με τον γονέα τους, επομένως μπορείτε να χρησιμοποιήσετε αυτό το μηχανισμό για να ζευγαρώσετε συναρτήσεις όποτε έχει νόημα χωρίς να μολύνετε το global namespace - «local globals» αν προτιμάτε. Η χρήση αυτής της τεχνικής θα πρέπει να γίνεται με περίσκεψη, αλλά είναι μια χρήσιμη δυνατότητα να υπάρχει.


Closures

Αυτό μας οδηγεί σε μία από τις πιο ισχυρές αφαιρέσεις που έχει να προσφέρει η JavaScript - αλλά ενδεχομένως και την πιο δύσκολη να την κατανοήσει κανείς. Τι κάνει αυτό;
 

κώδικας:

function makeAdder(a) {
    return function(b) {
        return a + b;
    }
}
x = makeAdder(5);
y = makeAdder(20);
x(6)
?
y(7)
?



Το όνομα της συνάρτησης makeAdder θα πρέπει να δίνει την απάντηση: δημιουργεί νέες προσθετικές συναρτήσεις οι οποίες όταν καλούνται με ένα όρισμα το προσθέτουν στο όρισμα με το οποίο δημιουργήθηκαν.

Αυτό που συμβαίνει εδώ είναι πάνω-κάτω το ίδιο με αυτό που συνέβαινε με τις ένθετες συναρτήσεις νωρίτερα: μια συνάρτηση ορισμένη μέσα σε μια άλλη έχει πρόσβαση στις μεταβλητές τις εξωτερικής συνάρτησης. Η μόνη διαφορά εδώ είναι ότι η εξωτερική συνάρτηση έχει ολοκληρωθεί, επομένως η κοινή λογική φαίνεται να λέει ότι οι τοπικές μεταβλητές της δεν υπάρχουν πια. Αλλά αυτές εξακολουθούν να υπάρχουν, διαφορετικά οι συναρτήσεις adder δε θα ήταν σε θέση να λειτουργήσουν. Και όχι μόνο αυτό αλλά υπάρχουν δύο «αντίγραφα» των τοπικών μεταβλητών της makeAdder, ένα που είναι 5 και ένα που είναι 20.

Να τι συνέβη στην πραγματικότητα. Κάθε φορά που η JavaScript εκτελεί μία συνάρτηση δημιουργεί ένα αντικείμενο scope (εμβέλεια) για να κρατήσει τις τοπικές μεταβλητές που υπάρχουν μέσα στη ρουτίνα. Αρχικοποιείται με όσες μεταβλητές πέρασαν ως παράμετροι της συνάρτησης. Αυτό είναι παρόμοιο με το global object όπου ζουν όλες οι global μεταβλητές και συναρτήσεις, αλλά με δύο σημαντικές διαφορές: πρώτον δημιουργείται ένα ολοκαίνουργιο αντικείμενο scope κάθε φορά που ξεκινά η εκτέλεση μιας συνάρτησης, και δεύτερο, αντίθετα με το global object (που στους browsers είναι προσβάσιμο ως window) αυτά τα αντικείμενα scope δε μπορούν να τύχουν άμεσου χειρισμού από τον κώδικα JavaScript. Δεν υπάρχει για παράδειγμα μηχανισμός που να μας επιτρέπει να διατρέξουμε τις ιδιότητες του τρέχοντος αντικειμένου scope.

Έτσι όταν καλείται η makeAdder δημιουργείται ένα αντικείμενο scope με μία ιδιότητα: a, η οποία είναι το όρισμα που περάστηκε στη συνάρτηση makeAdder. Η makeAdder μετά επιστρέφει μια ολοκαίνουργια συνάρτηση. Κανονικά σε αυτό το σημείο ο garbage collector της JavaScript θα μάζευε το αντικείμενο scope που δημιουργήθηκε για την makeAdder, αλλά η συνάρτηση που επεστράφη διατηρεί μια αναφορά σε αυτό το αντικείμενο scope. Σαν αποτέλεσμα το αντικείμενο scope δεν πρόκειται να συλλεχθεί από τον garbage collector μέχρις ότου πάψουν να υπάρχουν αναφορές στη συνάρτηση-αντικείμενο που επέστρεψε η makeAdder.

Τα αντικείμενα scope σχηματίζουν μία αλυσίδα που ονομάζεται scope chain, παρόμοια με την αλυσίδα των prototypes που χρησιμοποιούνται από το σύστημα αντικειμένων της JavaScript.

Μία closure είναι ο συνδυασμός μίας συνάρτησης και του αντικειμένου scope στο οποίο δημιουργήθηκε.

Οι closures σας επιτρέπουν να αποθηκεύσετε δεδομένα κατάστασης (state), και ως τέτοιες μπορούν συχνά να χρησιμοποιηθούν στη θέση αντικειμένων.


Διαρροές μνήμης

Μια δυσάρεστη παρενέργεια των closures είναι ότι κάνουν ιδιαίτερα εύκολη τη διαρροή μνήμης (memory leak) στον Internet Explorer. Η JavaScript είναι μία γλώσσα garbage collected - τα αντικείμενα κατά τη δημιουργία τους καταλαμβάνουν χώρο στη μνήμη και αυτή η μνήμη ανακτάται από τον browser όταν δεν απομένουν άλλες αναφορές στο αντικείμενο. Τα αντικείμενα που παρέχει το περιβάλλον τα διαχειρίζεται το ίδιο το περιβάλλον.

Οι browsers χρειάζεται να διαχειριστούν ένα μεγάλο αριθμό από αντικείμενα που αντιπροσωπεύουν την εκάστοτε HTML σελίδα - τα αντικείμενα του DOM. Είναι ευθύνη του browser να διαχειριστεί τη δέσμευση και αποδέσμευση της μνήμης.

Ο Internet Explorer χρησιμοποιεί το δικό του σύστημα garbage collection γι αυτά τα DOM αντικείμενα, ξεχωριστά από το μηχανισμό που χρησιμοποιεί η JavaScript. Είναι η αλληλεπίδραση μεταξύ των δύο που μπορεί να γίνει αιτία για διαρροές μνήμης.

Μια διαρροή μνήμης συμβαίνει στον IE κάθε φορά που σχηματίζεται μία κυκλική αναφορά ανάμεσα σε ένα αντικείμενο JavaScript και ένα DOM αντικείμενο. Θεωρήστε το εξής:
 

κώδικας:

function leakMemory() {
    var el = document.getElementById('el');
    var o = { 'el': el };
    el.o = o;
}



Η κυκλική αναφορά που σχηματίστηκε εδώ προκαλεί διαρροή μνήμης. Ο IE δε θα αποδεσμεύσει τη μνήμη που είναι σε χρήση για τα αντικείμενα el και o μέχρις ότου ο browser κάνει ολική επανεκκίνηση.

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

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

Οι closures κάνουν εύκολη την ακούσια δημιουργία διαρροών μνήμης. Δείτε αυτό:
 

κώδικας:

function addHandler() {
    var el = document.getElementById('el');
    el.onclick = function() {
        this.style.backgroundColor = 'red';
    }
}



Ο παραπάνω κώδικας ορίζει το στοιχείο που με κλικ θα γίνει κόκκινο. Επίσης δημιουργεί διαρροή μνήμης. Γιατί; Διότι η αναφορά στο el έχει πιαστεί ακούσια από την closure που δημιουργήθηκε για την ανώνυμη εσωτερική συνάρτηση. Αυτό δημιουργεί μία κυκλική αναφορά ανάμεσα σε ένα αντικείμενο JavaScript (τη συνάρτηση) και ένα εγγενές DOM αντικείμενο (το el).

Υπάρχει μια σειρά από workarounds γι αυτό το πρόβλημα. Το απλούστερο είναι:
 

κώδικας:

function addHandler() {
    var el = document.getElementById('el');
    el.onclick = function() {
        this.style.backgroundColor = 'red';
    }
    el = null;
}



Αυτό λειτουργεί με το να σπάει την κυκλική αναφορά.

Αναπάντεχα, ένα τρικ για το σπάσιμο μιας κυκλικής αναφοράς που προκλήθηκε από μια closure είναι η προσθήκη μίας ακόμα closure:
 

κώδικας:

function addHandler() {
    var clickHandler = function() {
        this.style.backgroundColor = 'red';
    }
    (function() {
        var el = document.getElementById('el');
        el.onclick = clickHandler;
    })();
}



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

Ένα άλλο καλό τρικ για την αποφυγή των closures είναι το σπάσιμο των κυκλικών αναφορών κατά το συμβάν window.onunload. Πολλές βιβλιοθήκες συμβάντων θα αναλάβουν να το κάνουν για λογαριασμό σας.

Share this post


Link to post
Share on other sites
Guest selldeadfulluk333

Hi all !
I have UK fullz dead , if u want to buy i have:

UK FULLZ RANDOM ---->>>>
4658652008699022|12/25|545|Name on Card : Mr. Lewis Crabtree |1 pengover close liskeard |Liskeard |Pl14 3nz|UK|phone number : 07463983223|date of birth : 01/04/1994|Mother's maiden name: Crabtree |account number : 33785939|sort code : 20-50-40|Full Name : L m crabtree

Uk Fullz with BANK i have ( Halifax, RBS, Santander, Natwest, HSBC, Bank of scotland, Barclays , Lloyds, First Direct, TSB, COOP, Metro, Nationwide, Yorkshire, UlsterBank, Clydesdale, Tesco, Monzo, Ireland, Issuing Bank, Revolut, Starling ) ----->>>>>

4751 2902 3460 8842|01|24|148|A a narma|33, 33 Beaumont Road||LE5 3HB|UK\phone number : 07413325093|date of birth : 07/05/1993|account number : 71240578|sort code: 60-15-48|mother maiden name : Khalifa |Full name: Asjad NARMA 

Uk Fullz with mobile network providers ( VODAFONE , O2 , EE...) ----->>>>>

Username : dwf3658@me.com
Password : Enigmatic1958
--------------EE Billing-----------------------
Full Name            :  David Foster
Address 1            : 34 Adelaide Road
Address 2            : West Ealing
City                      : London
County                 : Select County
Post Code            : W13 9EB
Phone Number     : 07931712570
--------------EE Fullz-----------------------
Card Holder Name    : D W FOSTER
Card Number            : 4659 2300 7263 0170
Expiry Date               : 08/23
CVV                          : 707
DOB(DD/MM/YYYY)                  : 03/06/1958
Account Number       : 20371858
Sort Code                 : 20-17-18
MMN                 : McLennan
|--------------- I N F O | I P -------------------|
|Client IP         : 86.250.26.253
|--- http://www.geoiptool.com/?IP=86.250.26.253 ----
User Agent         : Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_6) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0 Safari/605.1.15
|----------------

Uk Fullz with PHONE PROVIDER ----->>>>>

Username           : ruthieokane@googlemail.com
Password            : Hockey50
--------------O2 Billing-----------------------
Full Name            : Ruth O'Kane
Address 1            : 30 Ballymacashen Road
Address 2            : Killinchy
City                      : Newtownards
County                 : Down
Post Code            : BT24 6SH
Phone Number     : 07821923157
--------------O2 Fullz-----------------------
Card Holder Name    : MRS R O'KANE 
Card Number            : 4751 1100 1381 5188
Expiry Date               : 06 / 24
CVV                          : 134
DOB(DD/MM/YYYY)                  : 21/08/1961
Account Number       : 56523084
Sort Code                 : 98-00-30
MMN       : McCully
|--------------- I N F O | I P -------------------|
|Client IP         : 92.41.138.95
|--- http://www.geoiptool.com/?IP=92.41.138.95 ----
User Agent         : Mozilla/5.0 (Linux; Android 10; SAMSUNG SM-A920F) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/12.0 Chrome/79.0.3945.136 Mobile Safari/537.36
|----------- ((())) --------------|

Uk Fullz with AGE RANGE ----->>>>>
I have all DOB from 1930s-2000s

Uk Fullz with SORTCODE ----->>>>>
I have over 100k fullz so u can send any sortcode i will check for u

Uk Fullz with NIN ----->>>>>
Full name: Michael  Enomah 
Telephone: 07459192535
Date of birth: 14/03/1963
Email: mikeenomah@gmail.com
Address: 66 peninsula house o'Leary street , Warrington, Wa27sa
MMN: Agnes Ikhelua 
Card BIN: 465902
Cardholder name: M.Enomah
Card number: 4659024519856021
Card exp: 02/23
Security code: 059
Account: 43479765
Sort Code: 20-91-48
NIN: Sy 48 86 55 d
DL: ENOMA603143M99MM
Submitted by: 83.137.6.226
Location: 83.137.6.226
UserAgent: Mozilla/5.0 (Linux; Android 10; SAMSUNG SM-A505FN) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/12.1 Chrome/79.0.3945.136 Mobile Safari/537.36
Browser:

Uk Fullz with SPECIFIC DOOR ----->>>>>
Almost all have house numbers including floors and apartments

Uk Fullz with VBV + MMN ----->>>>>
4757149145425726|03 / 20|429|ERIN PATTERSON|4 Carsons Dale|Newtownards|Northern Ireland|BT23 5GG|UK|07754740429| DOB 9-4-1998 |account number 9382450401 |short code 09-01-28 |MMN McCormick |VBV bubbles\par

Uk Fullz with CITY----->>>>>
I have over 100k fullz, SO i can filter anycity u want

Uk Fullz with NATIONAL INSURANCE ----->>>>>

+ ---------------DVLA----------------+
+ Personal Information
+ ------------------------------------------+
| Email Address: shannon.lee96@hotmail.com
| First Name: Shannon
| Last Name: Lee
| Address: 393 Beaumont Leys Lane
| County: Leicestershire
| Postcode: LE4 2BG
| Date of Birth (dd/mm/yyyy): 26/12/1996
| Mobile/Telephone Number: 07833495581
| Driver License Number: 
| National Insurance Number: Jw 44 64 72 a
| Account Number: 46691713
| Sort Code: 09-01-28
+ ------------------------------------------+
+ Card Information
+ ------------------------------------------+
| Cardholder Name: S m Lee
| Card Number: 4757147329496307
| Expiry Date: 05/21
| CVV: 865
+ ------------------------------------------+
+ Bank Information
+ ------------------------------------------+
| Santander Customer ID: S m lee
| Santander Passcode: harry2803
| Santander Password: harry2803
| Santander Memorable Word: Harrybirthday

Uk Fullz with Driver License ----->>>>>

+ Personal Information
+ ------------------------------------------+
| Email Address: obrien50@gmx.co.uk
| First Name: Rose
| Last Name: O'brien
| Address: 15 Snowdon Drive, Fforestfach
| City: SWANSEA
| County: Swansea
| Postcode: SA5 5BD
| Date of Birth (yyyy/mm/dd): 23/07/1960
| Mobile/Telephone Number: 7480133262
| Driver License Number: OBRIE657230RA9VU
+ ------------------------------------------+
+ Card Information
+ ------------------------------------------+
| Cardholder Name: Rose O'brien
| Card Number: 4659352514485102
| Expiry Date: 04/23
| CVV: 632
| Account Number: 38732381
| Sort Code: 07-04-36
| MMN: Davies 


Also if you request anything in FULLZ we still meet
ALL OF THEM ARE FRESH FULLZ DEAD AND NOT RESOLD.

Please contact me
ICQ 713086896
Telegram @selldeadfullz

#deadfullz 
#fullzdead 
#uk 
#deadfullzuk 
#fullzdeaduk 
#selldeadfullz 
#buydeadfullz 
#ukdeadfullz 
#ukfullzdead

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Sign in to follow this  

×