freestuff.gr αρχική σελίδα
 FAQFAQ    ΑναζήτησηΑναζήτηση   Λίστα ΜελώνΛίστα Μελών   Ομάδες ΜελώνΟμάδες Μελών   <b>Εγγραφή Μέλους</b>Εγγραφή Μέλους 
 ΠροφίλΠροφίλ   Επιλογές μέλους Επιλογές   Τα bookmarks μου Τα bookmarks μου   Προσωπικά μηνύματαΠροσωπικά μηνύματα 
  διαφήμιση  

Καλώς ήρθατε στο forum μας! Για να συμμετάσχετε στις συζητήσεις θα πρέπει να είσαστε μέλος. Γίνετε μέλος τώρα!.

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


 Forum index » Δημιουργία Web Sites, Γραφικών & Προγραμματισμός » JavaScript και Frameworks
Moderators:  Super-Moderators, WebDev Moderators
Εισαγωγή νέου Θέματος   Απάντηση στο Θέμα Σελίδα 1 από 2 [17 Μηνύματα]      Bookmarks Tags: javascript Mark the topic unread :: Προηγούμενο θέμα :: Επόμενο θέμα
Σελίδα:  1, 2 Επόμενο
ΑποστολέαςΜήνυμα
skeftomilos
Script Master

Μέλος από: 07 Ιαν 2005
Βοηθήματα: 33
Νέα: 1
Μηνύματα: 256+

Περιοχή: Αθήνα
View users profile
ΜήνυμαΣτις: 13 Μαρ 2006 04:49    Θέμα: Εισαγωγή στη σύγχρονη JavaScript Απάντηση με παράθεση  Mark this post and the followings unread

Τι θα λέγατε για ένα JavaScript tutorial γραμμένο από έναν guru της γλώσσας; Αν μάλιστα σας έλεγα ότι είναι δημοσιευμένο μόλις μια εβδομάδα πριν, κι έγινε αμέσως ανάρπαστο στο delicious; Οι αλλαγές που έχουν συντελεστεί τον τελευταίο καιρό στη φιλοσοφία αυτής της γλώσσας κάνουν τα παλιά tutorials να μοιάζουν απαρχαιωμένα στην καλύτερη περίπτωση, άχρηστα και επιβλαβή στη χειρότερη. Ο Simon Willison έγραψε το εν λόγω κείμενο στα πλαίσια μιας τρίωρης ομιλίας του, και είναι πολύ κατάλληλο για όσους γνωρίζουν προγραμματισμό και θέλουν να αποκτήσουν μερικές γερές βάσεις στη JavaScript. Όσοι το διαβάσετε θα μάθετε πράγματα που δε θα βρείτε σε βιβλία 1000 σελίδων, και επιπλέον θα ενημερωθείτε για τα IN και OUT του σύγχρονου web scripting. Το tutorial είναι εδώ: A (Re)-Introduction to JavaScript.

Όσοι από εσάς θα το προτιμούσατε στα ελληνικά, να το:
____________________________________________________________

Εισαγωγή

Το όνομά μου είναι Simon Willison και ο τίτλος αυτής της παρουσίασης είναι «Επαν-εισαγωγή στη JavaScript».

Γιατί χρειάζεται μια νέα εισαγωγή; Διότι η 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[i]
}


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

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


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

κώδικας:
for (var i = 0, item; item = a[i]; 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[i];
    }
    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[i];
    }
    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[i];
    }
    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[i];
    }
    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]; 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]; 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[i];
    }
    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. Πολλές βιβλιοθήκες συμβάντων θα αναλάβουν να το κάνουν για λογαριασμό σας.
____________________________________________________________

Ο Simon Willison εργάζεται για την Yahoo!, και στο blog του κάνει συχνές αναφορές σε θέματα JavaScript. Ακόμα θα είναι ένας από τους ομιλητές του συνεδρίου @media2006. Το παραπάνω κείμενο μεταφράστηκε χωρίς την άδειά του, αλλά υποθέτω ότι δε θα έχει αντίρρηση.

_________________
The pure and simple truth is rarely pure and never simple. Ο μη νους δε σκέπτεται μη σκέψεις για το τίποτα.
ThyClub
Honorary Member

Μέλος από: 17 Νοε 2003
Βοηθήματα: 8
Νέα: 2
Templates: 3
Scripts: 5
Μηνύματα: 256+

Περιοχή: Hell's Kitchen
View users profile Visit posters website
portfolio facebook twitter deviantART digg del.icio.us 
skype 
ΜήνυμαΣτις: 13 Μαρ 2006 09:32    Θέμα: Απάντηση με παράθεση  Mark this post and the followings unread

omg!!!
softius
Script Master

Μέλος από: 11 Ιαν 2004
Μηνύματα: 241

View users profile Send email to user Visit posters website
ΜήνυμαΣτις: 14 Μαρ 2006 07:26    Θέμα: Απάντηση με παράθεση  Mark this post and the followings unread

Όποιος ενδιαφέρεται υπάρχει διαθέσιμο και το slideshow της ομιλίας του. Ακόμη μία πολύ καλή δουλειά εκ μέρους του. Νομίζω η μετάφραση, άξιζε τον κόπο, γιατί θα βοηθήσει αρκετούς!
cherouvim
Script Master

Μέλος από: 13 Ιουλ 2005
Βοηθήματα: 7
Νέα: 1
Scripts: 1
Μηνύματα: 256+

Περιοχή: Athens, Greece
View users profile Visit posters website
blog linkedin twitter 
ΜήνυμαΣτις: 14 Μαρ 2006 08:38    Θέμα: Απάντηση με παράθεση  Mark this post and the followings unread

Sygharitiria gia ti metafrasi kai gia to epikairo yliko pou panta prosfereis.

_________________
blog
alkisg


Μέλος από: 03 Ιουν 2005
Βοηθήματα: 1
Μηνύματα: 256+

Περιοχή: Ιωάννινα
View users profile Visit posters website
ΜήνυμαΣτις: 14 Μαρ 2006 08:42    Θέμα: Απάντηση με παράθεση  Mark this post and the followings unread

Καλό ε! Καλό ε! Καλό ε!
gre85


Μέλος από: 14 Απρ 2005
Μηνύματα: 11
Περιοχή: πειραιας
View users profile Send email to user
ΜήνυμαΣτις: 16 Μαρ 2006 15:05    Θέμα: Απάντηση με παράθεση  Mark this post and the followings unread

πολυ καλο...
cherouvim
Script Master

Μέλος από: 13 Ιουλ 2005
Βοηθήματα: 7
Νέα: 1
Scripts: 1
Μηνύματα: 256+

Περιοχή: Athens, Greece
View users profile Visit posters website
blog linkedin twitter 
ΜήνυμαΣτις: 16 Μαρ 2006 16:20    Θέμα: Απάντηση με παράθεση  Mark this post and the followings unread

Ante na erthei kai i 15h Iouniou... /http://www.vivabit.com/atmedia2006/sessions/#dom

_________________
blog
Basilakis
PHP Moderator

Μέλος από: 17 Νοε 2003
Βοηθήματα: 68
Νέα: 7
Templates: 3
Scripts: 3
Μηνύματα: 256+

Περιοχή: Womans' Brain
View users profile Send email to user Visit posters website
blog deviantART flickr myspace facebook linkedin 
hi5 sync twitter deviantART skype 
ΜήνυμαΣτις: 17 Μαρ 2006 14:17    Θέμα: Απάντηση με παράθεση  Mark this post and the followings unread

Kataplhktiko skeftomilos... Congats...

_________________
Κατασκευη Ιστοσελιδων
melodos


Μέλος από: 07 Φεβ 2007
Μηνύματα: 4
Περιοχή: Σάμη, Κεφαλονιά
View users profile Send email to user Visit posters website
ΜήνυμαΣτις: 30 Μαρ 2007 20:16    Θέμα: Thankssss
Περιγραφή θέματος: Συγχαρητήρια
Απάντηση με παράθεση  Mark this post and the followings unread

Πολλές ευχαριστίες για την μετάφραση...
ξανά ευχαριστώ!!!

_________________
Ρωμανός ο Μελωδός
dimsis
Reporter

Μέλος από: 25 Ιουλ 2001
Βοηθήματα: 9
Νέα: 89
Μηνύματα: 256+


View users profile
ΜήνυμαΣτις: 31 Μαρ 2007 08:10    Θέμα: Απάντηση με παράθεση  Mark this post and the followings unread

skeftomilos καταρχήν grand Respect!
2ον πως θα γίνει να μαζευτούν όλα τα code tutorials σε κανένα site αποκλειστικά για coders να τα έχουμε προσβάσιμα εύκολα και απλά;
Γιάννη (cordis) τι λες;
Κεντρικές κατηγορίες από α) web design β) desktop programming γ) web programming δ) databases κλπ και υποκατηγορίες Flash, PHP, Javascript, MySQL, SQL Server κλπ κλπ και μέσα τα καλύτερα tutorials από εδώ (αλλά και από οποιονδήποτε άλλο ενδιαφερθεί);
Έχει μερικά Ελληνικά sites που το παλεύουν να κάνουν κάτι τέτοιο, αλλά όλο και κάπου πάσχουν είτε από interface, είτε από οργάνωση, είτε από δημοσιότητα, είτε από ευκολία κλπ κλπ

Το είχα κάνει παλιά στο code.gr (σαν εσωτερικό sub-site) και είχε τους φανατικούς οπαδούς του. Δεν ήταν πολλοί σε αριθμό, αλλά όσοι ασχολούνται με το "άθλημα" το είχαν εκτιμήσει και στέλνανε υλικό... όπως είχα γράψει και εγώ διάφορα δικά μου. Όλα ακόμα υπάρχουν (λογικά) σε κάποιο backup...
EkLekTos
WebDev Moderator

Μέλος από: 07 Απρ 2005
Βοηθήματα: 40
Νέα: 2
Templates: 11
Μηνύματα: 256+

Περιοχή: Inside the Effects
View users profile
facebook linkedin twitter 
ΜήνυμαΣτις: 31 Μαρ 2007 23:54    Θέμα: Απάντηση με παράθεση  Mark this post and the followings unread

uparxei idi omws http://www.freestuff.gr/tutorials/ giati na ginei allo..
Gia mena den krinetai kapoio tutorial kalo i kako alla kala grammeno kai kaka grammeno, kai to paramikro bothima pou mporei na ginei kapoion se kapoion tha xreiastei den paei na pei pws oloi tha to diabasoun, eksalou ta tutorials ginetai gia autous pou ta xreiazontai kai oxi gia olous . Elipizw na katalabes ti ennow

_________________
* Apple Technical Support Specialist *
* Apple Sales & Product Professional Certificate since 2011 *
Follow me @Twitter
skeftomilos
Script Master

Μέλος από: 07 Ιαν 2005
Βοηθήματα: 33
Νέα: 1
Μηνύματα: 256+

Περιοχή: Αθήνα
View users profile
ΜήνυμαΣτις: 01 Απρ 2007 11:50    Θέμα: Απάντηση με παράθεση  Mark this post and the followings unread

Μια πρόσφατη φωτογραφία του Simon Willison, από συνέντευξη στο Vitamin


_________________
The pure and simple truth is rarely pure and never simple. Ο μη νους δε σκέπτεται μη σκέψεις για το τίποτα.
dimsis
Reporter

Μέλος από: 25 Ιουλ 2001
Βοηθήματα: 9
Νέα: 89
Μηνύματα: 256+


View users profile
ΜήνυμαΣτις: 01 Απρ 2007 12:29    Θέμα: Απάντηση με παράθεση  Mark this post and the followings unread

EkLekTos ανέφερε:
uparxei idi omws http://www.freestuff.gr/tutorials/ giati na ginei allo..
Gia mena den krinetai kapoio tutorial kalo i kako alla kala grammeno kai kaka grammeno, kai to paramikro bothima pou mporei na ginei kapoion se kapoion tha xreiastei den paei na pei pws oloi tha to diabasoun, eksalou ta tutorials ginetai gia autous pou ta xreiazontai kai oxi gia olous . Elipizw na katalabes ti ennow


Με το σκεπτικό σου θα πρέπει να μπουν στα tutorials και όλες οι απαντήσεις που έχουμε δώσει π.χ. με κώδικα σε όσους έχουν ζητήσει βοήθεια στο forum που είναι εκατοντάδες. Θα 'ταν καλό πάντως αυτά τα tutorials (αλλά και άλλα) που έχει και στην αντίστοιχη ενότητα εδώ ο Γιάννης, να τα βρίσκαμε και σε ένα ξεχωριστό domain αποκλειστικά για αυτό το σκοπό. Αν έχει ο Γιάννης κανένα ελεύθερο domain και την διάθεση για κάτι τέτοιο, θα μπορούσε να το κάνει.
geoki


Μέλος από: 07 Ιαν 2002
Βοηθήματα: 1
Μηνύματα: 256+

Περιοχή: Giannitsa
View users profile
ΜήνυμαΣτις: 07 Απρ 2007 04:03    Θέμα: Απάντηση με παράθεση  Mark this post and the followings unread

Ευχαριστούμε skeftomilos φοβερή δουλειά
fusion


Μέλος από: 23 Αυγ 2008
Μηνύματα: 146
Περιοχή: Λάρισα
View users profile
blog twitter 
ΜήνυμαΣτις: 21 Σεπ 2008 15:06    Θέμα: Απάντηση με παράθεση  Mark this post and the followings unread

Εχω ξεκινησει να το διαβαζω, πολυ ενδιαφερον...
Μαγκας ο skeftomilos

_________________
Ακολουθήστε με στο Twitter
Εμφάνιση Μηνυμάτων:   
Εισαγωγή νέου Θέματος   Απάντηση στο Θέμα Σελίδα 1 από 2 [17 Μηνύματα] Σελίδα:  1, 2 Επόμενο
Mark the topic unread :: Προηγούμενο θέμα :: Επόμενο θέμα
 Forum index » Δημιουργία Web Sites, Γραφικών & Προγραμματισμός » JavaScript και Frameworks


Σχετικά θέματα
 Θέματα   Απ/σεις   Αποστολέας   Τελευταίο μήνυμα 
javascript disabled 0 Serghio 27 Σεπ 2016 10:10
Serghio Εμφάνιση τελευταίου μηνύματος
Υπαρχει καποιος Guru στην javascript? 13 thanatoz 22 Νοε 2015 23:55
ailouros Εμφάνιση τελευταίου μηνύματος
 
Τώρα είναι 31 Μαρ 2017 02:34 | All times are UTC + 2


Email This Page to Someone! add to Favorites

     Powered by p h p B B © 2001,2005 p h p B B Group
Για άμεση επικοινωνία με τον διαχειριστή του freestuff.gr στο email: freestuff.gr(παπάκι)gmail.com


Copyright © 1999-2013 Freestuff.gr All Rights Reserved  
Version Aegean, designed by N. Tsaganos