-
Notifications
You must be signed in to change notification settings - Fork 14
/
index_it.html
1019 lines (907 loc) · 67.3 KB
/
index_it.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<title>
jQuery vs MooTools: Come scegliere tra due i grandi framework JavaScript
</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<link rel="Shortcut Icon" href="favicon.ico" type="image/x-icon">
<link rel="stylesheet" href="css/blueprint/screen.css" type="text/css" media="screen, projection">
<link rel="stylesheet" href="css/blueprint/print.css" type="text/css" media="print">
<!--[if IE]><link rel="stylesheet" href="css/blueprint/ie.css" type="text/css" media="screen, projection"><![endif]-->
<link rel="stylesheet" href="css/blueprint/src/typography.css" type="text/css" media="screen" title="no title" charset="utf-8">
<style>
body {
font-size: 100%;
color: #444;
background: #fff;
font-family: "Georgia", Arial, Helvetica, sans-serif;
}
h1, h2, h3, h4 {
color: #626262;
}
h1 {
text-align: center;
margin: 20px !important;
font-size: 90px;
padding: 0 !important;
padding:0 0 10px;
}
div.caption {
font-size: 14px;
text-align: right;
margin: auto;
width: 800px;
position: relative;
top: -25px;
background-color: none;
}
a, a.visited {
color: #004d9b;
text-decoration: none;
}
a:hover {
text-decoration: underline;
}
p.footnote {
font-size: 12px;
text-align:right;
margin-top: 0px;
position: relative;
top: -8px !important;
top: 0px;
}
p.about {
font-size: 12px;
}
tr td {
border-bottom: 1px solid #999;
vertical-align: top;
}
tr th {
background: #999;
color: #fff;
}
.dsq-item-cp {
display: none;
}
div.trans {
font-size: 10px;
}
ul#dsq-comments {
max-height:800px !important;
overflow:auto !important;
padding:0 10px 0 0 !important;
}
</style>
<script src="http://www.google.com/jsapi"></script>
<script>
google.load("mootools", "1.2.2");
</script>
<script src="js/Lighter/Ligher.uncompressed.js" type="text/javascript" charset="utf-8"></script>
<script>
window.addEvent('domready', function(){
var toc = $$('ul a');
$$('a:not(.stbutton)').each(function(a) {
if (toc.contains(a)) return;
a.set('target', '_blank');
});
if (Browser.Engine.trident) return;
// Highlight all "pre" elements in a document.
$$('pre').light({
altLines: 'hover',
indent: 2,
mode: 'pre',
path: 'js/Lighter/'
});
});
</script>
</head>
<body>
<div class="container">
<h1 class="span-24 last">jQuery vs MooTools</h1>
<div class="caption">
Maggio 2009 - <a href="http://www.clientcide.com" target="_blank">Aaron Newton, Clientcide</a><br />
Traduzione di <a href="http://www.lorenzostanco.com">Lorenzo Stanco</a> e <a href="http://www.twitter.com/stecb">Stefano Ceschi Berrini</a>
<div class="trans">
Also available in
<a href="/index_pt-br.html">Portuguese (Brazil)</a>, <a href="/index_cn.html">Chinese</a>, <a href="index_fa.html">Farsi (Persian)</a> and <a href="/index_es-ar.html">Spanish</a>. | <a href="http://wiki.github.com/anutron/jquery-vs-mootools">How to submit a translation</a>.
</div>
</div>
<p>
Sempre più spesso chi si avvicina alla programmazione in JavaScript si imbatte nella difficile scelta della libreria da adottare, o quantomeno della prima da imparare. Se lavori all'interno di un team probabilmente già ti è stato imposto un framework, con motivazioni più o meno discutibili. Se questo è il tuo caso, se sei costretto a usare <a href="http://www.mootools.net">MooTools</a> ma sei pratico con <a href="http://www.jquery.com">jQuery</a>, allora questo articolo può ugualmente esserti d'aiuto.
</p>
<p>
<a href="http://twitter.com/joshink/statuses/1671986611">Ogni</a> <a href="http://twitter.com/jezusisstoer/statuses/1642244246">giorno</a> <a href="http://twitter.com/digitalcampaign/statuses/1622094648">su</a> <a href="http://twitter.com/jesswma/statuses/1605733380">Twitter</a> leggo innumerevoli post del tipo "MooTools o jQuery?". Questo articolo vuole aiutarti a scegliere.
</p>
<h3>Premessa</h3>
<p>
Sono uno sviluppatore MooTools. Lavoro sul framework MooTools. Scrivo un blog su MooTools. Ho scritto <a href="http://www.mootorial.com">il principale tutorial online</a> e <a href="http://www.amazon.com/gp/product/1430209836?ie=UTF8&tag=clientside-20&link_code=as3&camp=211189&creative=373489&creativeASIN=1430209836">il libro su MooTools</a>. Ovviamente ho una visione che è in qualche modo di parte. E ammetto anche di non usare molto spesso jQuery. Se sei uno sviluppatore jQuery e pensi che abbia travisato qualcosa, ti prego di contattarmi e aiutarmi a rimediare l'errore. Il mio obiettivo è quello di esser d'aiuto - non quello di vendere un framework piuttosto che un altro.
</p>
<h3>Scopo</h3>
<p>
Aiutarti a scegliere tra questi due framework significa per me spiegartene le differenze. Comincio col dire che <b>entrambi sono scelte eccellenti</b>. Non esiste la scelta sbagliata. Entrambi i framework hanno i loro punti di forza e le loro debolezze, ma, in generale, sono entrambi ottime scelte. Ci sono anche ulteriori framework che fanno bene il loro lavoro. <a href="http://www.dojotoolkit.org/">Dojo</a>, <a href="http://www.prototypejs.org/">Prototype</a>, <a href="http://developer.yahoo.com/yui/">YUI</a>, <a href="http://extjs.com/">Ext</a> e altri ancora sono ottime opzioni. La scelta, in verità, ha più a che fare con il tuo stile personale e con i tuoi bisogni. L'articolo si concentra su MooTools e jQuery, in quanto sono sempre più i framework presi in considerazione dalla maggior parte delle persone. Non cercherò di convincere nessuno a passare da un framework a un altro. Entrambi offrono spunti interessanti da cui è possibile imparare molto. Se vuoi saperne di più su questo articolo e del perché l'ho scritto puoi leggere il <a href="http://www.clientcide.com/3rd-party-libraries/jquery-vs-mootools-mootools-vs-jquery/">mio post sul blog di Clientcide</a>.
</p>
<h3>Indice</h3>
<ul>
<li><a href="#mottos">Il Motto Dice Tutto</a></li>
<li><a href="#learning">La Curva di Apprendimento e la Community</a></li>
<li><a href="#javascript">I Punti di Forza di JavaScript</a></li>
<ul style="margin-bottom: 0px">
<li><a href="#dom">Non Solo il DOM</a></li>
<li><a href="#inheritance">L'Ereditarietà in JavaScript</a></li>
<li><a href="#self">Autoreferenza</a></li>
</ul>
</li>
<li><a href="#jsfun">MooTools Rende JavaScript Più Divertente</a></li>
<li><a href="#domfun">jQuery Rende il DOM Più Divertente</a></li>
<li><a href="#cando">Qualunque Cosa Tu Faccia, Io Posso Farla Meglio</a></li>
<li><a href="#yourway">MooTools Fa Ciò Che Vuoi Come Vuoi</a></li>
<li><a href="#chaining">La Concatenazione Come Design Pattern</a></li>
<li><a href="#reuse">Riutilizzo del Codice con jQuery</a></li>
<li><a href="#classes">Riutilizzo del Codice con MooTools</a>
<ul>
<li><a href="#mooinheritance">L'Ereditarietà in MooTools</a></li>
<li><a href="#extension">Estendere ed Implementare le Classi</a></li>
</ul>
</li>
<li><a href="#conclusion">È ora di decidere</a></li>
<li><a href="#discussion">Commenti</a></li>
</ul>
<h2>Qualche dato</h2>
<table>
<tr>
<th></th>
<th>jQuery Core</th>
<th>MooTools Core</th>
</tr>
<tr>
<td>Dimensione</td>
<td>55.9K</td>
<td>64.3K</td>
</tr>
<tr>
<th colspan="3">Caratteristiche</th>
</tr>
<tr>
<td>Licenza</td>
<td><a href="http://en.wikipedia.org/wiki/MIT_License" title="MIT License">MIT</a> & <a href="http://en.wikipedia.org/wiki/GPL" title="GPL">GPL</a></td>
<td><a href="http://en.wikipedia.org/wiki/MIT_License" title="MIT License">MIT</a></td>
</tr>
<tr>
<td>Strumenti per il DOM</td>
<td>sì</td>
<td>sì</td>
</tr>
<tr>
<td>Animazioni</td>
<td>sì</td>
<td>sì</td>
</tr>
<tr>
<td>Gestione degli eventi</td>
<td>sì</td>
<td>sì</td>
</tr>
<tr>
<td>Selettori CSS3</td>
<td>sì (un sottoinsieme)</td>
<td>sì (un sottoinsieme)</td>
</tr>
<tr>
<td>Ajax</td>
<td>sì</td>
<td>sì</td>
</tr>
<tr>
<td>Estensioni ai tipi nativi (eccetto Element)</td>
<td>circa una dozzina per Array, Object e String</td>
<td>circa sei dozzine per Array, Object, String, Function e Number</td>
</tr>
<tr>
<td>Ereditarietà</td>
<td>Non supportata direttamente da jQuery</td>
<td>Fornita col costruttore <em><a href="http://mootools.net/docs/core/Class/Class">Class</a></em></td>
</tr>
<tr>
<th colspan="3">Altre considerazioni</th>
</tr>
<tr>
<td>Plugin</td>
<td>Centinaia di plugin non ufficiali su <a href="http://plugins.jquery.com/">plugins.jquery.com</a></td>
<td>Circa 4 dozzine di plugin ufficiali disponibili su <a href="http://mootools.net/more">mootools.net/more</a>. Plugin non ufficiali su <a href="http://mootools.net/plugins">mootools.net/plugins</a>.</td>
</tr>
<tr>
<td>Libreria ufficiale per la UI</td>
<td>sì</td>
<td>no</td>
</tr>
</table>
<p class="footnote">
Informazioni basate sui dati forniti da <a href="http://jquery.com">jquery.com</a>, <a href="http://mootools.net">mootools.net</a> e <a href="http://en.wikipedia.org/wiki/Comparison_of_JavaScript_frameworks">wikipedia.com</a>.
</p>
<a name="mottos"></a>
<h2>Il Motto Dice Tutto</h2>
<p>
Se si va sul sito di jQuery, all'inizio della pagina c'è scritto:
</p>
<blockquote>jQuery è una libreria JavaScript veloce e concisa che semplifica la navigazione del documento HTML, la gestione degli eventi, le animazioni e le interazioni Ajax per un rapido sviluppo web. jQuery è progettato per cambiare il modo in cui si scrive JavaScript.</blockquote>
<p>
...mentre se si va sul sito di MooTools, ecco cosa si troverà scritto:
</p>
<blockquote>MooTools è un framework JavaScript Object-Oriented compatto e modulare, progettato per lo sviluppatore JavaScript medio/avanzato. Permette di scrivere codice potente, flessibile e cross-browser con le sue eleganti, ben documentate e coerenti API.</blockquote>
<p>
Penso che questo dica già tutto. Se vuoi sapere cosa ne penso io (e stai leggendo, quindi assumo che tu lo voglia), la domanda non è quale sia il framework migliore o peggiore. Quale delle cose scritte qui sopra vuoi fare? Questi due frameworks non stanno cercando di fare le stesse cose. Si sovrappongono un po' rispetto alle funzionalità che mettono a disposizione, ma non stanno cercando di fare le stesse cose.
</p>
<p>
La descrizione di jQuery stesso parla di HTML, eventi, animazioni, Ajax e sviluppo web. MooTools parla di orientamento agli oggetti (OOP) e riguarda lo scrivere codice potente e flessibile. jQuery aspira a "cambiare il modo di scrivere JavaScript" mentre MooTools è progettato per lo sviluppatore JavaScript medio/avanzato.
</p>
<p>
Parte di questa considerazione deriva dalla nozione di <em>framework</em> e <em>toolkit</em>. MooTools è un <em>framework</em> che cerca di implementare JavaScript <em>come dovrebbe essere</em> (in accordo con gli autori di MooTools). Lo scopo è quello di implementare una API che sembra JavaScript puro e che lo esalti; non riguarda solamente il DOM. jQuery è un <em>toolkit</em> che mette a disposizione un insieme di metodi facili da utilizzare in un sistema progettato per rendere il DOM stesso più piacevole. Accade spesso che il DOM sia l'area in cui la maggior parte delle persone scrive JavaScript, quindi in molti casi jQuery è tutto quello che serve.
</p>
<p>
Quando si scrive codice con MooTools si ha la sensazione di scrivere JavaScript puro. Se non si è interessati riguardo al JavaScript come linguaggio, imparare MooTools può sembrare un duro lavoro. Se si è invece interessati a JavaScript ed in particolare a cosa lo rende interessante, la potenza e l'espressività, beh, personalmente penso che MooTools sia la scelta migliore.
</p>
<a name="learning"></a>
<h2>La Curva di Apprendimento e la Community</h2>
<p>
Per prima cosa, jQuery è sicuramente più facile da imparare. Ha uno stile quasi colloquiale che neanche ti sembrerà di programmare. Se tutto quello che interessa è ottenere qualcosa che funzioni velocemente, senza dover imparare JavaScript, jQuery è probabilmente la scelta migliore. Non che MooTools non aiuti ad ottenere gli stessi risultati, ma ammetto che può essere più ostico da imparare se se si è principianti in JavaScript. Inoltre ci sono moltissime risorse che aiutano ad imparare jQuery - almeno, più di quelle che ci sono per imparare MooTools.
</p>
<p>
Se si mette a confronto la community di jQuery (<a href="http://docs.jquery.com/Discussion">vedi la pagina "Discussion"</a>) e quella
di MooTools (<a href="irc://irc.freenode.net/#mootools">irc</a>, <a href="http://groups.google.com/group/mootools-users">mailing list</a>,
e <a href="http://mooforum.net/">forum non ufficiale</a>) si notano subito due cose: 1) la community di jQuery è <i>molto</i>
più grande (personalmente attribuisco questo fatto a quanto detto prima sulla facilità di apprendimento, ma non solo...) e 2) sono
molto più attivi nel promuovere la libreria.
Misurando jQuery e MooTools sul numero degli utenti, sul numero delle ricerche su Google, sul numero di libri venduti, ecc,
jQuery stravince.
</p>
<p>
Detto questo, per spiegare perché si dovrebbe prendere in considerazione anche MooTools
devo prima mostrare cosa fanno i due framework (e come lo fanno).
Alla fine la scelta sarà dettata da cosa si vuol realizzare e da come si preferisce programmare
(e forse anche dal <i>se</i> piace programmare, almeno in JavaScript).
</p>
<a name="javascript"></a>
<h2>I Punti di Forza di JavaScript</h2>
<p>
Parte della decisione sta nel domandarsi che cosa si vuole fare con JavaScript. Consideriamo il JavaScript base. Senza nessun framework; solamente vecchio e puro JS. Mette a disposizione oggetti nativi come
<a href="https://developer.mozilla.org/En/Core_JavaScript_1.5_Reference/Global_Objects/String">Strings</a>, <a href="https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Global_Objects/Number">Numbers</a>, <a href="https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Global_Objects/Function">Functions</a>, <a href="https://developer.mozilla.org/En/Core_JavaScript_1.5_Reference/Global_Objects/Array">Arrays</a>, <a href="https://developer.mozilla.org/En/Core_JavaScript_1.5_Reference/Global_Objects/Date">Dates</a>, <a href="https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Global_Objects/RegExp">Espressioni regolari</a>, e più. Inoltre predispone un modello di ereditarietà - un qualche esoterico modello chiamato <a href="https://developer.mozilla.org/en/Core_JavaScript_1.5_Guide/Inheritance">ereditarietà prototipale</a> (ne parlerò più avanti). Questi blocchi portanti ed il concetto di ereditarietà sono pane e burro di ogni linguaggio di programmazione e non hanno assolutamente niente a che vedere con i browser o con il web o con CSS o HTML. Si potrebbe scrivere qualsiasi cosa si voglia con JavaScript. Tris, scacchi, photo editing, un server web, qualunque cosa. Il fatto è che il 99% di tutto il JS che c'è in giro lo vediamo eseguito sui browser ed è in questo contesto che lo pensiamo. Ossia il linguaggio di programmazione per il browser.
</p>
<p>
Sapere che il browser, il DOM, è l'area dove la maggior parte delle volte utilizziamo JavaScript ma che quest'ultimo è anche un linguaggio di programmazione molto robusto ed espressivo aiuterà a capire le differenze tra MooTools e jQuery.
</p>
<a name="dom"></a>
<h3>Non Solo il DOM</h3>
<p>
Se si pensa a cosa si vuole fare con JavaScript in termini di "prendere elementi nella pagina per farne qualcosa" allora jQuery è probabilmente la scelta migliore. Eccelle nell'offrire un sistema molto espressivo per descrivere il comportamento nelle pagine in un modo che quasi non sembra programmazione vera e propria. Si può sempre continuare ad usare il resto in JavaScript per fare quello che si vuole, ma se si è focalizzati sul DOM - per cambiare proprietà CSS, animare elementi, recuperare dei contenuti via Ajax, etc - tutto quello che si vorrà fare sarà ottenibile tramite jQuery, più qualcosa - se mancante in jQuery - in vecchio e puro JavaScript. jQuery mette anche a disposizione metodi che non riguardano prettamente il DOM; ad esempio, offre un meccanismo per iterare sugli array - <i><a href="http://docs.jquery.com/Utilities/jQuery.each">$.each(array,fn)</a></i> - oppure, ad esempio, offre un metodo per il trim delle stringhe - <a href="http://docs.jquery.com/Utilities/jQuery.trim">$.trim(str)</a></i>. Ma non sono presenti molti metodi di questo tipo, che è un bene, perché, per la maggior parte, se si stanno solo prendendo elementi dal DOM, ci si itera sopra, e li si altera (aggiungendo HTML, cambiando stili, aggiungendo dei listener per eventi quali click e mouseover, etc) non serve molto altro.
</p>
<p>
Ma se si pensa al JavaScript nella sua totalità, si può notare come jQuery non si focalizzi in cose al di fuori del DOM. Questa è una delle ragioni per cui è così facile da imparare, ma altresì limita il modo in cui può aiutare a scrivere JavaScript. Vuol essere niente più che un solido sistema di programmazione per il DOM. Non prevede ereditarietà e nemmeno dispone di utilità per tutti i tipi nativi del linguaggio JavaScript, ma non ne ha la necessità. Se si vogliono fare magie con stringhe, date, espressioni regolari, array e funzioni, è possibile. Ma aiutare in questo non è compito di jQuery. JavaScript come linguaggio è quello che serve. jQuery rende il DOM il tuo ambiente, ma il resto del linguaggio JavaScript è fuori dalla sua ottica.
</p>
<p>
È qui la differenza maggiore rispetto a MooTools. Piuttosto che focalizzarsi esclusivamente sul DOM (comunque, e ci tornerò piu avanti, offre tutte le stesse funzionalità di jQuery ma consegue lo scopo in maniera totalmente differente), MooTools prende sotto suo dominio tutto l'intero linguaggio. Se jQuery rende il DOM l'ambiente operativo, MooTools mira a rendere tutto JavaScript come ambiente operativo, e questa è una delle ragioni per cui è più ostico da imparare.
</p>
<a name="inheritance"></a>
<h3>L'Ereditarietà in JavaScript</h3>
<p>
Il linguaggio di programmazione JavaScript offre alcune cose veramente fantastiche a riguardo. Per i principianti, è un <a href="http://en.wikipedia.org/wiki/Functional_programming">linguaggio funzionale</a>, significa che tratta le funzioni come oggetti di ordine superiore che possono essere passati come variabili praticamente come tutti gli altri oggetti - stringhe o numeri ad esempio. È progettato su questo concetto base e molti dei metodi e dei pattern presenti funzionano al meglio quando il codice viene scritto in questo modo. È la differenza tra:
</p>
<pre class="js">for (var i = 0; i < myArray.length; i++) { /* fai qualcosa */ }</pre>
<p>
e:
</p>
<pre class="js">myArray.forEach(function(item, index) { /* fai qualcosa */ });</pre>
<p>
JavaScript ha un <a href="https://developer.mozilla.org/en/Core_JavaScript_1.5_Guide/Inheritance">modello di ereditarietà</a> che non è unico ma piuttosto raro nei linguaggi di programmazione. Invece dell'ereditarietà a classi (una classe può essere sottoclasse etc) JS vira verso l'ereditarietà prototipale. Questo significa che gli oggetti ereditano direttamente da altri oggetti. Se si referenzia una proprietà in un oggetto che eredita da un altro oggetto, il linguaggio ispeziona l'oggetto figlio per quella proprietà e, se non la trova, la cerca nel padre. Questo è il modo in cui funziona sugli array. Quando si scrive:
</p>
<pre class="js">[1,2,3].forEach(function(item) { alert(item) }); //alert di 1 poi 2 ed infine 3</pre>
<p>
il metodo "<a href="https://developer.mozilla.org/En/Core_JavaScript_1.5_Reference:Objects:Array:forEach">forEach</a>" non è una proprietà dell'array che viene dichiarato ([1,2,3]), ma è una proprietà del prototipo per tutti gli Array. Quando si referenzia questo metodo il linguaggio cerca forEach nell'array, e, non trovandolo, guarda all'interno del prototipo 'padre' di tutti gli array. Questo significa che il metodo forEach non è in memoria per ogni array dichiarato; è in memoria soltanto per il prototipo degli array. In due parole: efficienza e potenza. (nota: l'alias utilizzato in MooTools per forEach è each)
</p>
<a name="self"></a>
<h3>Autoreferenza</h3>
<p>
In JavaScript esiste una keyword speciale: "this". È difficile per me in poche parole definirla ma, di default, "this" è l'oggetto al quale il metodo corrente appartiene. Permette agli oggetti di riferirsi a se stessi all'interno dei loro metodi, in quanto altrimenti non avrebbero altri mezzi per farlo. Tutto questo inizia a diventare importante quando si creano oggetti figli e numerose istanze di quell'oggetto; come altro potrebbe il metodo di un oggetto riferirsi all'oggetto stesso? Quando la copia attuale del metodo esiste nel padre, non nel figlio, la keyword "this" permette a queste istanze di riferirsi al loro stato. (<a href="http://www.quirksmode.org/js/this.html">qui c'è una piu completa descrizione a riguardo</a>, ed <a href="https://developer.mozilla.org/En/Core_JavaScript_1.5_Reference/Operators/Special_Operators/This_Operator">un'altra da Mozilla</a>)
</p>
<p>
La keyword "this" permette agli oggetti che ereditano da altri oggetti di riferirsi a loro stessi, ma ci sono volte in cui si vorrebbe far riferimento a qualcos'altro attraverso il "this". Questo procedimento è chiamato <a href="http://alternateidea.com/blog/articles/2007/7/18/javascript-scope-and-binding">binding</a>, ossia quando si specifica un "this" <i>diverso</i> per un metodo. Il metodo "each" (del tipo Array) permette di specificare l'oggetto a cui far riferimento attraverso un secondo argomento. Qui sotto c'è un esempio che esplica il passaggio di un "this" differente:
</p>
<pre class="js">var ninja = {
weapons: ['katana', 'throwing stars', 'exploding palm technique'],
log: function(message) {
console.log(message);
},
logInventory: function() {
this.weapons.each(function(weapon) {
//vogliamo che "this" faccia riferimento a ninja...
this.log('this ninja can kill with its ' + weapon);
}, this); //quindi passiamo "this" (che è ninja) ad Array.each
}
};
ninja.logInventory();
//this ninja can kill with its katana
//this ninja can kill with its throwing stars
//this ninja can kill with its exploding palm technique</pre>
<p>
Nell'esempio qui sopra, "leghiamo" ninja (che è il "this" dentro al metodo <em>logInventory</em>) al metodo che passiamo all'array in modo che ci si possa riferire alla proprietà log di ninja. Se non l'avessimo fatto, "this" sarebbe stato <em>window</em>.
</p>
<p>
Questi sono solamente alcuni esempi del potere e dell'espressività che JavaScript ha da offrire - ereditarietà, auto referenza e binding, ed efficienti proprietà prototipali. La brutta notizia riguarda il fatto che JavaScript puro non rende queste cose potenti molto usabili o accessibili, ed è qui che <i>entra in gioco</i> MooTools. Rende questi tipi di pattern semplici ed anche piacevoli da usare. Si finisce per usare codice piu astratto, ed a lungo andare, è una buona cosa - una cosa potente. Capire come questi patterns siano preziosi e come usarli correttamente richiede uno sforzo, ma la cosa positiva è che il codice che si scrive è molto più riusabile e facile da mantenere. Andrò nei dettagli a riguardo tra un minuto.
</p>
<a name="jsfun"></a>
<h2>MooTools Rende JavaScipt Più Divertente</h2>
<p>
Dato che MooTools si focalizza nel rendere le API JavaScript stesse piu stabili e coerenti, perde un po' nel dare un'interfaccia che "cambia il modo in cui si scrive JavaScript" e nel rendere JavaScript nell'insieme meno frustrante; MooTools è un'estensione del linguaggio JavaScript. MooTools prova a rendere il JavaScript così com'è stato pensato. Una parte significativa del "core" viene utilizzata per arricchire Funzioni, Stringhe, Array, Number, Element ed altri prototipi. L'altro enorme aspetto del "core" di MooTools è che offre una funzione chiamata <em><a href="http://mootools.net/docs/core/Class/Class">Class</a></em>.
</p>
<p>
Ora, attraverso <em>Class</em> sembrerebbe si stesse cercando di ricreare un più classico modello di ereditarietà che si puo trovare in Java o C++, ma <a href="https://developer.mozilla.org/en/Core_JavaScript_1.5_Guide/Class-Based_vs._Prototype-Based_Languages">non è così</a>. Quello che fa <em>Class</em> è rendere il modello di ereditarietà prototipale del JavaScript più facile ed accessibile e qualcosa da cui prendere vantaggio. Da notare che questi concetti non sono unici in MooTools (altri frameworks offrono funzionalità similari), ma non sono presenti in jQuery. Quest'ultimo non offre un sistema di ereditarietà né offre estensioni per gli oggetti nativi (Function, String, etc). Sia chiaro, non è un difetto di jQuery, in quanto i suoi autori potrebbero rendere facilmente disponibili queste cose. Loro hanno invece progettato un toolkit con un obiettivo diverso in mente. Mentre MooTools mira a rendere JavaScript più divertente, jQuery mira a rendere il DOM più divertente ed i progettisti hanno scelto di limitare i loro scopi a questi compiti.
</p>
<a name="domfun"></a>
<h2>jQuery Rende il DOM Più Divertente</h2>
<p>
Ed è per questo che jQuery è più accessibile. Non presuppone che si impari JavaScript in lungo ed in largo. Non mette di fronte l'ereditarietà prototipale, binding, "this" e prototipi nativi. Quando si inizia a scrivere codice con jQuery tramite il <a href="http://docs.jquery.com/Tutorials:How_jQuery_Works">tutorial ufficiale</a>, questo è il primo esempio che ci si trova davanti:
</p>
<pre class="js">window.onload = function() {
alert("benvenuto");
}</pre>
<p>e qui c'è il terzo: </p>
<pre class="js">$(document).ready(function() {
$("a").click(function(event) {
alert("Grazie della visita!");
});
});</pre>
<p>
Se si legge il <a href="http://www.amazon.com/gp/product/1430209836?ie=UTF8&tag=clientside-20&link_code=as3&camp=211189&creative=373489&creativeASIN=1430209836">libro su MooTools</a> oppure il <a href="http://www.mootorial.com/wiki">tutorial di MooTools</a> (dei quali ne sono l'autore) questi approcciano in maniera completamente differente. Mentre si può saltare gran parte ed andare direttamente ad imparare cose su effetti e DOM, se si vuol imparare seriamene MooTools, bisognerebbe iniziare con cose come <em>Class</em>, e, lo ammetto, se si è alle prime armi con la programmazione, o si vuol solamente qualcosa che funzioni nel proprio sito senza approfondire il linguaggio JavaScript, jQuery sicuramente risulterà molto più semplice ed "amichevole".
</p>
<p>
D'altra parte, se si vuol veramente imparare JavaScript, MooTools è un gran bel mezzo per riuscirci. Implementa molte cose che JavaScript deve ancora avere (molti dei metodi che estendono i tipi nativi sono solo le specifiche <a href="https://developer.mozilla.org/En/New_in_JavaScript_1.8">js 1.8</a> ed oltre). Se si è abituati a programmare, specialmente sia programmazione orientata agli oggetti che funzionale, MooTools offre tantissimi design patterns interessanti ed espressivi.
</p>
<a name="cando"></a>
<h2>Qualunque Cosa Tu Faccia, Io Posso Farla Meglio</h2>
<p>
Se si guarda a quello che jQuery può fare, c'è sempre una stessa funzionalità in MooTools. Riguardo quello che MooTools può fare, non c'è modo a volte di emularle in codice jQuery dato che quest'ultimo si focalizza solamente sul DOM. MooTools ha più funzionalità di jQuery, ma non c'è niente in jQuery che permetta di emularle. Ad esempio, jQuery non fornisce nessun sistema di ereditarietà, ma non c'è problema. Si potrebbe, se si vuole, utilizzare il modulo <em>Class</em> di MooTools in aggiunta a jQuery. C'è inoltre un <a href="http://code.google.com/p/jquery-inheritance/updates/list">plugin che mette a disposizione l'ereditarietà in jQuery</a> (non l'ho utilizzato, ma penso offra più o meno lo stesso tipo di funzionalità)
</p>
<p>Se vediamo questo pezzo di codice jQuery dall'esempio sopra:</p>
<pre class="js">$(document).ready(function() {
$("a").click(function(event) {
alert("Grazie per la visita!");
});
});</pre>
<p>
e volessimo 'tradurlo' in MooTools, avremmo:
</p>
<pre class="js">window.addEvent('domready', function() {
$$('a').addEvent('click', function(event) {
alert('Grazie per la visita!');
});
});</pre>
<p>
Sono molto simili no?
</p>
<p>
Prendiamo ora un esempio un po' più complesso in jQuery:
</p>
<pre class="js">$(document).ready(function() {
$("#orderedlist li:last").hover(function() {
$(this).addClass("green");
},
function() {
$(this).removeClass("green");
});
});</pre>
<p>
ed in MooTools diverrà:
</p>
<pre class="js">window.addEvent('domready',function() {
$$('#orderedlist li:last-child').addEvents({
mouseenter: function() {
this.addClass('green');
},
mouseleave: function() {
this.removeClass('green');
}
});
});</pre>
<p>
Ancora, molto simili. Direi che la versione MooTools è più esplicita, ma anche molto verbosa. È chiaro che leggendo il codice MooTools si intuisca che stiamo aggiungendo due eventi - uno per l'entrata del mouse e l'altro per l'uscita del mouse, mentre la versione jQuery è più concisa; il suo metodo <em><a href="http://docs.jquery.com/Events/hover">hover</a></em> accetta due metodi - il primo per l'entrata del cursore del mouse ed il secondo per l'uscita del cursore del mouse. Io personalmente preferisco il codice MooTools in quanto è più leggibile, ma è un'osservazione prettamente personale.
</p>
<p>
Devo dire inoltre che qualche volta jQuery può diventare troppo esoterico per i miei gusti. I metodi non sempre hanno senso per me ed a prima vista li trovo difficili da analizzare. Comunque, anche se non sarebbe molto giusto da dire dato che sono in intimità con MooTools, per me leggere MooTools è più facile. Una delle cose che apprezzo di MooTools riguarda il fatto che praticamente tutti i nomi dei metodi e delle classi danno il vero nome alle cose. I metodi sono quasi sempre verbi e lasciano pochi dubbi riguardo quello che fanno. Ogni linguaggio di programmazione richiede una ricerca nella documentazione per la sintassi quando si scrive il codice - Non parlo di questo. Sto dicendo solamente che trovo le API di MooTools più coerenti e consistenti.
</p>
<a name="yourway"></a>
<h2>MooTools Fa Ciò Che Vuoi Come Vuoi</h2>
<p>
E se ti piace la sintassi jQuery? Un modo per illustrare il potere di MooTools è mostrare quanto facile sia cambiare il codice in modo che si addica ai propri gusti. Se avessimo voluto implementare il metodo <em>hover</em> da jQuery a MooTools, avremmo potuto facilmente fare così:</p>
<pre class="js">Element.implement({
hover : function(enter,leave){
return this.addEvents({ mouseenter : enter, mouseleave : leave });
}
});
//e quindi lo si potrà usare esattamente come nella versione jQuery:
$$('#orderlist li:last').hover(function(){
this.addClass('green');
},
function(){
this.removeClass('green');
});
</pre>
<p>
Ci sono addirittura plugins MooTools che fanno questo; <a href="http://github.com/cheeaun/mooj/tree/master">forniscono una sintassi jQuery per MooTools</a>. Il focalizzarsi di MooTools riguardo l'estensibilità significa che si può implementare praticamente qualsiasi cosa si voglia. Questo è qualcosa che jQuery non può fare. MooTools può simulare jQuery volendo, ma jQuery non può mimare MooTools. Se si vogliono scrivere classi oppure estendere i prototipi nativi o fare qualcosa che MooTools può fare, avendo adottato jQuery bisognerà farlo a mano.
</p>
<a name="chaining"></a>
<h2>La Concatenazione Come Design Pattern</h2>
<p>
Facciamo un altro di questi esperimenti. Qui sotto c'è del codice jQuery (dal tutorial ufficiale):
</p>
<pre class="js">$(document).ready(function() {
$('#faq').find('dd').hide().end().find('dt').click(function() {
$(this).next().slideToggle();
});
});</pre>
<p>
Questo è un esempio di sintassi che personalmente non mi alletta. Guardando il codice qui sopra, non sono molto sicuro di quello che stia facendo. In particolare sarei curioso di capire cosa fa <em>.end</em> e come <em>.find</em>, che lo segue, sia in relazione a quello che fa <em>.end</em>. Ora, guardando la documentazione jQuery si capisce benissimo cosa fa <em>.end </em>(resetta il valore del selettore originale, in questo caso #faq). Ma a me sembra strano. Quando lavoro con jQuery, spesso mi ritrovo ad essere insicuro riguardo cosa faccia un particolare metodo. Ovviamente ciò riguarda solo me dato che jQuery viene utilizzato da tantissime persone (che sono contente di usarlo), quindi anche questa è una preferenza personale.
</p>
<p>
Vediamo la logica spiegata sopra in MooTools:
</p>
<pre class="js">window.addEvent('domready', function() {
var faq = $('faq');
faq.getElements('dd').hide();
faq.getElements('dt').addEvent('click', function() {
this.getNext().slide('toggle');
});
});
</pre>
<p>
Ancora, il codice scritto con MooTools è più verboso, ma anche più esplicito. Si nota pure che il design pattern in questo caso riguarda salvare l'elemento #faq in una variabile (dove jQuery usa il metodo <em>.end</em> per ritornarla). Faccio notare che è possibile anche in MooTools scrivere codice concatenato. Ad Esempio:
</p>
<pre class="js">item.getElements('input[type=checkbox]')
.filter(function(box) {
return box.checked != checked;
})
.set('checked', checked)
.getParent()[(checked) ? 'addClass' : 'removeClass']('checked')
.fireEvent((checked) ? 'check' : 'uncheck');</pre>
<p>
Comunque, scrivere codice come questo - con molta logica dentro domready - con entrambi i frameworks, direi che è una brutta abitudine. È' molto meglio incapsulare la logica in moduli riusabili.
</p>
<a name="reuse"></a>
<h2>Riutilizzo del codice con jQuery</h2>
<p>
È molto allettante quando si lavora ad un progetto web scrivere del codice in questo modo. Basta soltanto aggiungere un po' di logica nella pagina per selezionare gli elementi del DOM e "settarli" nascondendone alcuni, alterandone degli altri, ed aggiungendo degli event listeners per i click ed i mouseover. Sviluppare il codice in questo modo è molto efficiente, molto veloce. Il problema che nasce scrivendo tutta la propria logica all'interno della funzione associata alla domready riguarda il fatto che molti pezzi di codice fanno le stesse cose ma in posti differenti. Se prendiamo il pattern FAQ descritto sopra potremmo applicare la stessa logica in qualche altra parte in una pagina differente con qualsiasi lista di termini e definizioni. Si dovrà ripetere la stessa logica ogni volta che si troverà questo pattern?
</p>
<p>
Un metodo semplice per rendere il codice riusabile si ottiene "impacchettando" la logica in una funzione e passandogli degli argomenti. Qui di seguito ecco come si potrebbe fare in jQuery:
</p>
<pre class="js">function faq(container, terms, definitions) {
$(container).find(terms).hide().end().find(definitions).click(function() {
$(this).next().slideToggle();
});
};
$(document).ready(function() {
faq('#faq', 'dd', 'dt');
});</pre>
<p>
Questo metodo è migliore per due ragioni importantissime:
</p>
<ol>
<li>
Se in futuro ci sarà bisogno di cambiare il modo in cui queste liste funzionano (ad esempio se si volesse tener traccia dei click in un log web oppure se si volessero recuperare le definizioni tramite ajax) potremmo solamente cambiare il nostro metodo <i>faq</i> invece che andare a modificare svariate copie ovunque. Di questo ne tengo una piccola traccia nella mia applicazione. Tenendo appunto traccia dei punti dove la mia applicazione tocca il codice generico, sarà più facile sistemare i bugs, aggiornare i frameworks, aggiungere features, o alterare funzionalità.
</li>
<li>
La seconda: c'è meno codice. Riusando lo stesso metodo più volte, non bisognerà ripetersi e questo è un valore aggiunto in ogni ambiente di programmazione. Rende inoltre il codice che i visitatori devono scaricare meno pesante.
</li>
</ol>
<p>
jQuery attualmente ha un metodo un po' più rifinito per scrivere "widget" riusabili come questi. Piuttosto che incoraggiare a mettere tutto dentro funzioni come nell'esempio qui sopra (che è piuttosto rudimentale), incoraggia a scrivere plugins jQuery. In questo modo:
<pre class="js">jQuery.fn.faq = function(options) {
var settings = jQuery.extend({
terms: 'dt',
definitions: 'dd'
}, options);
//"this" è il contesto corrente; in questo caso, gli elementi ai quali vogliamo applicare un layout faq
$(this).find(settings.terms).hide().end().find(settings.definitions).click(function() {
$(this).next().slideToggle();
});
return this;
};</pre>
</p>
che di conseguenza si potrebbe usare così:
</p>
<pre class="js">$('#faq').faq();</pre>
<p>
Guardando all'esempio qui sopra, non c'è molta differenza tra dichiarare la nostra funzione <i>faq</i> in questo modo e dichiararla come una funzione vera e propria. Non è nel namespace globale, ma potremmo aggiungerlo facilmente. Rendendolo plugin jQuery potremmo quindi concatenarlo ad altri suoi metodi. L'altro beneficio riguarda il "this" che all'interno della nostra funzione è il contesto corrente dell'elemento nella concatenazione jQuery in quel momento. Utilizzando questo pattern per i plugins si potrà essere in grado di renderli parte integrante di jQuery, ma a parte quello, un plugin è praticamente una singola funzione che prende il contesto corrente jQuery, ci fa qualcosa, e poi ritorna il contesto per il prossimo elemento nella catena. Non è molto complesso il discorso, ed infatti questo rende molto semplice per chiunque scrivere plugins jQuery - sono solamente delle singole funzioni.
</p>
<p>
Si noti che è possibile scrivere plugins jQuery più complessi con i metodi e gli stati. Questo tipo di pattern è supportato dal sistema di plugins jQuery UI e non usa lo stesso meccanismo del plugin di base (come il nostro esempio delle faq). Invece, si attacca un oggetto con metodi e proprietà all'oggetto jQuery (i.e. <em>$.ui.tabs</em>). C'è un modo semplice per invocare questo oggetto (<em>$(selector).tabs()</em>) cosicché si possa continuare a concatenare come nel plugin faq. Dato che non ritorna una referenza all'oggetto tabs creato per gli elementi nel nostro selettore, si è forzati a chiamare ancora il selettore per invocarci metodi. Invece di chiamare <em>myTabInstance.add(url, label, index)</em> bisognerà eseguire un'altra volta il selettore e chiamare la funzione (come stringa): <em>$(selector).tabs('add',url,label, index)</em>. Questo significa che si stanno valutando i selettori 2 volte (a meno che non si salvino in una variabile da qualche parte), e che non si ha mai un puntatore al metodo "add" che renda possibile un <em>bind</em> oppure un <em>delay</em>. Questo post comunque è focalizzato sui core di MooTools e jQuery, e mentre il sistema jQuery UI fornisce questa funzionalità, non è qualcosa che è disponibile in jQuery di default.
</p>
<a name="classes"></a>
<h2>Riutilizzo del Codice con MooTools</h2>
<p>
In MooTools quando si vuol definire un pattern, si tende o ad usare <em><a href="http://mootools.net/docs/core/Class/Class">Class</a></em> oppure si implementa un metodo in un oggetto nativo (su <em>String</em>, ad esempio).
</p>
<p>
Piuttosto che dare un linguaggio completamente differente dallo stile nativo di JavaScript, MooTools cerca di stare in mezzo alla definizione di una sintassi personalizzata e l'estensione dei design patterns propri di JavaScript. Uno dei modi in cui lo fa è tramite l'estensione dei prototipi degli oggetti nativi nel linguaggio e nel DOM. Questo significa che se ci fosse bisogno di un metodo che fa il trim di una stringa, MooTools incoraggia ad aggiungere quel metodo nell'oggetto String (notare che <em><a href="http://mootools.net/docs/core/Native/String#String:trim">String.trim</a></em> è già presente in MooTools; non serve aggiungerlo a mano):
</p>
<pre class="js">String.implement({
trim: function() {
return this.replace(/^\s+|\s+$/g, '');
}
});</pre>
<p>
Questo significa che si può solamente eseguire <i>" non più spazi alla fine! ".trim()</i> ed ottenere <i>"non più spazi alla fine!"</i>. Alcuni direbbero che implementare proprietà direttamente nei prototipi nativi è inappropriato. È questa la ragione per la quale MooTools e <a href="http://www.prototypejs.org/">Prototype.js</a> non possono essere usati assieme - i framework che manipolano i prototipi dei tipi nativi non possono essere usati con altri frameworks che fanno lo stesso. Se si definisce <i>String.prototype.foo()</i> ed un'altra libreria nella stessa pagina definisce lo stesso, 'vince' il metodo che viene definito per ultimo. In un certo modo, si può dire che è lo stesso problema che si incontra con il namespace globale <em>window</em>. Comunque è così che funziona JavaScript. È in questo modo che <a href="https://developer.mozilla.org/En/New_in_JavaScript_1.8">JavaScript 1.8</a> ha aggiunto moltissime features. Le aggiunge direttamente ai prototipi.
</p>
<p>
Gli sviluppatori MooTools hanno lavorato in modo che il framework sia semplice da estendere e da utilizzare nella sua totalità, senza ricorrere ad altri frameworks. Inoltre sarebbe scortese domandare agli utenti di scaricare due frameworks diversi. La sola ragione valida per includere due frameworks riguarda il voler usufruire di plugins per entrambi, e nella mente degli autori di MooTools (io compreso), se si vuole un plugin che non è disponibile per il framework adottato, sarebbe più appropriato spendere del tempo per fare il porting per il proprio ambiente piuttosto che far scaricare agli utenti un altro framework.
</p>
<p>
Una volta che si è capito come funziona JavaScript e si è realizzato il potere dell'estensione dei tipi nativi, si scoprirà un nuovo metodo di programmazione. Si potranno scrivere plugins che alterano Elements, oppure Dates, o Functions. Mentre qualcuno direbbe che aggiungere metodi ai tipi nativi è "sporco", io dico che è proprio questa la feature principale di JavaScript. È una sua caratteristica architetturale. Aggiungendo metodi ai tipi nativi il codice risulterà conciso e compartimentalizzato. Anche jQuery utilizza questo metodo, ma limita il prototyping al solo oggetto jQuery (alias <em>$</em>).
</p>
<p>
Mentre si possono concatenare chiamate a metodi sull'oggetto jQuery, negli altri tipi di oggetti non si potrà fare una concatenazione. Ad esempio, se si vuole in jQuery fare il trim di una stringa e poi iterare ogni riga, si dovrebbe scrivere:
</p>
<pre class="js">$.each( $.trim( $('span.something').html() ).split("\n"), function(i, line){alert(line);});</pre>
<p>In MooTools invece, dato che si modificano i prototipi, si può fare questo:</p>
<pre class="js">$('span.something').get('html').trim().split("\n").each(function(line){alert(line);});</pre>
<p>
Solamente guardando a questo esempio risulta estremamente chiara la potenza dell'estensione dei prototipi. Il concatenamento negli elementi del DOM non è il solo posto dove risulta utile. MooTools fa si che si possano concatenare chiamate a metodi su tutti gli oggetti, incluse chiamate ad un metodo su più elementi in una singola volta.
</p>
<p>
La chiave qui, ed è il cuore del framework MooTools, è il guidare a programmare ciò che si vuole. Se una funzionalità non è presente nel core, lo si può estendere aggiungendola. L'obiettivo del core non è provvedere ad ogni singola funzionalità possibile ed immaginabile, ma è mettere a disposizione gli strumenti per scrivere ciò che si vuole. Una grossa parte riguarda la facilità con la quale si possono estendere i tipi nativi, traendo vantaggio dall'ereditarietà prototipale. Si possono fare tutte queste cose in JavaScript nativo, ma MooTools rende il tutto più semplice e più piacevole.
</p>
<a name="mooinheritance"></a>
<h3>L'Ereditarietà in MooTools</h3>
<p>
Nonostante il suo nome, in MooTools la funzione <em>Class</em> non è veramente una classe e non crea classi. Ha uno schema di progettazione che potrebbe ricordare le classi di un
linguaggio di programmazione tradizionale, ma in realtà <em>Class</em> riguarda sempre oggetti ed ereditarietà prototipale. (Sfortunatamente la parola "class"
è quella che meglio descrive queste cose, quindi nell'articolo quando parlo di "classi" faccio riferimento a funzioni che ritornano oggetti - che chiamerò
"istanze" - che ereditano da un prototipo.)
</p>
<p>
Per creare una classe, si deve passare un oggetto al costruttore <em>Class</em> in questo modo:
</p>
<pre class="js">//classe per gli essere umani
var Human = new Class({
initialize: function(name, age) {
this.name = name;
this.age = age;
},
isAlive: true,
energy: 1,
eat: function() {
this.energy = this.energy + 1; //oppure this.energy++
}
});</pre>
<p>
Passando l'oggetto a <em>Class</em> (nell'esempio abbiamo passato un oggetto con proprietà e metodi come "isAlive" e "eat") l'oggetto diventa il prototipo
di ogni istanza di quella classe. Dopo aver creato la classe, è possibile crearne le istanze, ad esempio:
</p>
<pre class="js">var bob = new Human("bob", 20); //bob si chiama "bob" e ha 20 anni.</pre>
<p>
Ora abbiamo una istanza di <em>Human</em>. <em>bob</em> ha le proprietà dell'oggetto definito al momento della creazione della class <em>Human</em>.
Ma la cosa importante è che <em>bob</em> ha queste proprietà per ereditarietà. Quando facciamo riferimento a <i>bob.eat</i>, <i>bob</i> non
ha davvero quel metodo. JavaScript sa che <i>bob</i> non ha un metodo <i>eat</i>, e quindi lo cerca lungo la catena di ereditarietà,
trovandolo sull'oggetto che abbiamo passato quando abbiamo creato la classe <em>Human</em>. Questo vale anche per <i>energy</i>. A prima vista ciò
può sembrare sbagliato; non vogliamo che tutti gli umani acquisiscano energia ogni volta che <i>bob</i> mangia. La cosa importante da capire è
che appena assegniamo un valore all'energia di <i>bob</i>, assegniamo a <i>bob</i> un valore proprio, e non guardiamo più al valore del prototipo.
Perciò la prima volta che <i>bob</i> mangerà, acquisirà una sua definizione di <em>energy</em> (pari a 2).
</p>
<pre class="js">bob.eat(); //bob.energy == 2</pre>
<p>
Da notare che il nome e l'età di <em>bob</em> sono unicamente suoi; infatti queste due proprietà vengono ad esso assegnate durante l'inizializzazione
della classe, nel metodo <i>initialize</i>.
</p>
<p>
Tutto questo comportamento può sembrare un po' strano, ma il suo punto di forza sta nel fatto che possiamo definire funzionalità per un certo modello e
creare istanze di quel modello ogni volta che ne abbiamo bisogno. Ogni istanza manterrà il proprio stato. Dunque se creiamo un'altra
istanza, ciascuna sarà indipendente dalle altre, ma erediterà dallo stesso modello base:
</p>
<pre class="js">var Alice = new Human();
//alice.energy == 1
//bob.energy == 2</pre>
<p>
Le cose si fanno veramente interessanti quando cominciamo a sfruttare questo meccanismo aggiungendo dell'altro.
</p>
<a name="extension"></a>
<h3>Estendere ed Implementare le Classi</h3>
<p>
Proviamo a rivisitare il plugin jQuery per le <i>faq</i>. Cosa accadrebbe se volessimo aggiungere un'ulteriore funzionalità al plugin?
Se volessimo, ad esempio, fare una versione AJAX del plugin che legga le risposte alle domande dal server? Supponiamo che
il plugin <i>faq</i> sia stato scritto da qualcun altro e che vogliamo arricchirlo senza modificare in alcun modo l'originale.
</p>
<p>
Abbiamo solo due possibili scelte. O duplichiamo l'intera logica del plugin <i>faq</i> (ricordo, è una singola funzione),
praticamente realizzando un "fork", oppure lo invochiamo e aggiungiamo successivamente le nuove funzionalità ad esso.
Dovendo scegliere, la seconda alternativa pare quella meno faticosa. Il plugin diventerebbe allora qualcosa come:
</p>
<pre class="js">jQuery.fn.ajaxFaq = function(options) {
var settings = jQuery.extend({
//alcune opzioni specifiche per ajax, come l'url per la richiesta dei termini
url: '/getfaq.php'
definitions: 'dd'
}, options);
//"this" è il contesto corrente; in questo caso, gli elementi ai quali vogliamo applicare un layout faq
$(this).find(settings.definitions).click(function() {
$(this).load(.....); //la logica per caricare il contenuto dei termini
});
this.faq(); //chiamata al plugin originale faq
});</pre>
<p>
Questo codice ha alcuni lati negativi. Prima di tutto, la nostra classe <em>faq</em> ripete la selezione delle definizioni,
cosa che potrebbe anche essere pesante; non c'è alcun modo di memorizzare le definizioni recuperate e riutilizzarle
quando servono nuovamente. In secondo luogo, non possiamo aggiungere il codice per la gestione di ajax in mezzo a quello
per la visualizzazione delle definizioni, presente nel plugin originale. Il plugin originale chiama <em>slideToggle</em> per espandere le definizioni utilizzando
una animazione. Questo è un problema in quanto l'effetto sicuramente partirà prima che la nostra richiesta ajax finisca di caricare. Non c'è
nessuna soluzione definitiva se non quella di duplicare l'intero plugin <em>faq</em>.
</p>
<p>
Ora consideriamo la nostra classe <em>Human</em> realizzata con MooTools. Ha le proprietà <em>isAlive</em> e <em>energy</em> e ha un
metodo chiamato <em>eat</em>. Se volessimo creare una nuova versione di <em>Human</em> con proprietà aggiuntive?
Con MooTools possiamo estendere la classe in questo modo:
</p>
<pre class="js">var Ninja = new Class({
Extends: Human,
initialize: function(name, age, side) {
this.side = side;
this.parent(name, age);
},
energy: 100,
attack: function(target) {
this.energy = this.energy - 5;
target.isAlive = false;
}
});</pre>
<p>
Si può vedere come abbiamo aggiunto molte funzionalità in una sottoclasse.
Questa sottoclasse ha alcune proprietà che sono unicamente presenti nei <em>Ninja</em>.
I <em>Ninja</em> hanno una energia (<em>energy</em>) iniziale pari a 100, un orientamento (<em>side</em>) e un metodo <em>attack</em>
che gli permette di uccidere gli altri <em>Humans</em> a costo di alcuni punti <em>energy</em>.
</p>
<pre class="js">var bob = new Human('Bob', 25);
var blackNinja = new Ninja('Nin Tendo', 'unknown', 'evil');
//blackNinja.isAlive = true
//blackNinja.name = 'Nin Tendo'
blackNinja.attack(bob);
//bob non ha chance</pre>
<p>
Uccisioni a parte, ci sono alcune cose interessanti da considerare. Il metodo <em>initialize</em> nella classe
<em>Ninja</em> sembra ridefinire, sovrascrivendo, il metodo <em>initialize</em> della classe <em>Human</em>, ma è ancora
possibile accedere ad esso chiamando <em>this.parent</em>, passando quindi gli argomenti che il metodo <em>initialize</em> della classe padre si aspetta.
Inoltre possiamo decidere quando il nostro nuovo codice viene eseguito; prima o dopo la chiamata al padre. Possiamo assegnare nuovi valori alle proprietà
(come <em>energy</em>, pari a 100 anziché 1), e definire nuove funzionalità. Immagina se avessimo potuto fare questo nel nostro
plugin jQuery <em>faq</em>. Avremmo potuto caricare il nostro ajax e POI lanciare l'animazione di comparsa del contenuto.
</p>
<p>
MooTools ha un altro pattern chiamato Mixin. Invece di avere una
relazione padre-figlio definita creando una sottoclasse per estensione
di un'altra classe, è possibile anche definire una classe che
viene miscelata ad altre classi affinché possa mettere a
disposizione di queste le sue proprietà.
Ecco un esempio:
</p>
<pre class="js">//class guerriero (mixin)
var Warrior = new Class({
energy: 100,
kills: 0,
attack: function(target) {
target.isAlive = false;
this.energy = this.energy - 5;
this.kills++;
}
});</pre>
<p>
Abbiamo preso le qualità che rendono un <em>Ninja</em> diverso da un <em>Human</em> e le abbiamo messe in una classe a parte.
Questo ci permette di usare il codice non solo per i <em>Ninja</em>. Possiamo infatti mettere a disposizione dei
<em>Ninja</em> le qualità di <em>Warrior</em> (guerriero) in questo modo:
</p>
<pre class="js">var Ninja = new Class({
Extends: Human,
Implements: Warrior, //può essere un array se vogliamo implementare più di una classe
initialize: function(name, age, side) {
this.side = side;
this.parent(name, age);
}
});</pre>
<p>
<em>Ninja</em> funziona ancora come prima, ma <em>Warrior</em> è a nostra disposizione per essere riusato:
</p>
<pre class="js">var Samurai = new Class({
Extends: Human,
Implements: Warrior,
side: 'good' //orientamento "buono"
});</pre>
<p>
Ora abbiamo una classe <em>Samurai</em> e una classe <em>Ninja</em>. Si osservi quanto poco codice è stato
necessario per definirle. Sono simili tra loro, perché entrambi umani con abilità da guerriero,
ma sono differenti in quanto un samurai sarà sempre buono ("good"), mentre un ninja può cambiare il suo orientamento.
Spendendo un po' di tempo per scrivere una classe <em>Human</em> e una classe <em>Warrior</em>, siamo in grado di avere tre diverse
classi senza nessuna ripetizione di codice, mantenendo al tempo stesso un buon controllo sull'esecuzione dei metodi
e sulla loro relazione con gli altri. Ogni istanza che creiamo ha un proprio stato, e il codice in sé è molto leggibile.
</p>
<p>
Ora che abbiamo visto come funzionano le classi in MooTools, torniamo alla nostra classe jQuery <em>faq</em> e proviamo a
riscriverla in MooTools, aggiungendo poi la parte Ajax come abbiamo fatto con jQuery.
</p>
<pre class="js">
var FAQ = new Class({
//Options è un'altra classe, disponibile con MooTools
Implements: Options,
//queste sono le opzioni di default
options: {
terms: 'dt',
definitions: 'dd'
},
initialize: function(container, options) {
//memorizziamo un riferimento al contenitore
this.container = $(container);
//setOptions è un metodo messo a disposizione dal mixin Options,
//serve a "fondere" le opzioni di default con quelle passate al metodo
this.setOptions(options);
//memorizziamo termini e definizioni
this.terms = this.container.getElements(this.options.terms);
this.definitions = this.container.getElements(this.options.definitions);
//chiamiamo il metodo attach
//separare questo metodo dal costruttore rende la nostra classe più facile da estendere
this.attach();
},
attach: function(){
//cicla sui termini
this.terms.each(function(term, index) {
//aggiungi l'evento click a ognuno
term.addEvent('click', function(){
//il click chiama il metodo toggle sull'indice corrente
this.toggle(index);
}, this);
}, this);
},
toggle: function(index){
//apre la definizione per l'indice passato
this.definitions[index].slide('toggle');
}
});
</pre>
<p>
Però! È un sacco di codice. Anche se togliessimo tutti i commenti, sarebbero ancora due dozzine di linee.
Ho già mostrato come sia possibile realizzare questo plugin con più o meno la stessa quantità di codice
della versione jQuery. Allora perché questa versione è così tanto lunga? Beh, l'abbiamo resa molto più flessibile.
Per usare la classe ci basta chiamare il costruttore, in questo modo.
</p>
<pre class="js">var myFAQ = new FAQ(myContainer);
//volendo ora possiamo chiamare dei metodi:
myFAQ.toggle(2); //mostra il terzo elemento
</pre>
<p>
Possiamo accedere a metodi e proprietà dell'istanza. E la nostra versione ajax?
Il problema con jQuery era che non potevamo ritardare l'apertura animata della definizione
aspettando il completamento della richiesta ajax. Non abbiamo più questo problema con MooTools:
</p>
<pre class="js">FAQ.Ajax = new Class({
//questa classe eredita le proprietà della classe FAQ
Extends: FAQ,
//aggiungiamo anche un'altra opzione a quelle di default.
//questa à l'url, alla quale aggiungeremo l'indice del
//termine; veramente potremmo fare qualcosa di più robusto,
//ma come esempio va bene così
options: {
url: null;
},
//memorizzeremo i risultati delle chiamate ajax, così se una sezione verrà
//aperta due volte non avremo bisogno di interrogare nuovamente il server
indexesLoaded: [],
toggle: function(index){
//se abbiamo già caricato la definizione
if (this.indexesLoaded[index]) {
//ci basta chiamare la versione precedente di toggle
this.parent(index);
} else {
//altrimenti, invia la richiesta al server
new Request.HTML({
update: this.definitions[index],
url: this.options.url + index,
//e quando i dati sono pronti, espandi la definizione
onComplete: function(){
this.indexesLoaded[index] = true;
this.definitions[index].slide('toggle');
}.bind(this)
}).send();
}
}
});
</pre>
<p>
Ora abbiamo una versione della classe <em>FAQ</em> che ci permette di caricare le definizioni dal server.
Da notare che siamo riusciti ad integrare la nuova logica in modo da non far apparire la definizione
prima della ricezione del contenuto dal server (cosa che non potevamo fare nella versione jQuery).
Da notare anche come sia stato necessario descrivere solamente la nuova funzionalità (ajax) e poco altro.
Questa estensibilità rende possibile la creazione di famiglie di plugin che offrono diverse
sfumature di medesime funzionalità. Ciò significa anche che possiamo usare plugin scritti
da altri e modificarne solo quelle piccole parti che vogliamo diverse (senza dover duplicare tutto).
Questo spiega perché, data una certa funzione - un selettore di date, una interfaccia a tabs, etc -
si trovano pochi plugin per MooTools. Molti plugin infatti risolvono il problema oppure, se non lo fanno,
è possibile estenderli facilmente aggiungendo quello che serve.
</p>
<p>
Come ho illustrato prima, è possibile scrivere widget complessi con jQuery, con metodi e stato.
Gran parte del codice scritto facendo ciò è JavaScipt puro quando c'è necessita di
esprimere logiche non relative al DOM. Ma il modello di jQuery non offre un sistema per estendere queste
istanze in sottoclassi. E nemmeno aiuta con mixin riutilizzabili facilmente.
Infine, i plugin di jQuery sono sempre collegati a elementi del DOM. Se si vuole scrivere una classe
che, diciamo, elabora degli URL, non c'è un sistema con stato per fare cose di questo tipo, a meno che non lo si scriva appositamente.
</p>
<a name="conclusion"></a>
<h2>È ora di decidere</h2>
<p>
jQuery mira all'espressività, alla scrittura rapida e veloce di codice e al DOM, mentre MooTools mira ad estendibilità, ereditarietà,
leggibilità, riuso del codice e mantenibilità.
Puoi vederli come due punti opposti di una scala. Da una parte jQuery è qualcosa che ti permette di iniziare con semplicità ed avere subito il risultato,
ma (per mia esperienza) può trasformarsi in codice difficile da riutilizzare e mantenere (o meglio, questa è una tua responsabilità, non
un problema di jQuery in sè). Dall'altra parte MooTools necessita di più tempo per imparare e richiede più codice prima
che tu possa vedere i risultati del tuo lavoro, ma successivamente quello stesso codice sarà più riusabile e più mantenibile.
</p>
<p>
Né il nucleo <i>(core)</i> di MooTools né quello di jQuery forniscono tutte le funzionalità immaginabili. Entrambi i framework mantengono
un nucleo piuttosto snello, lasciando a te e agli altri sviluppatori la possibilità di creare plugin ed estensioni. Il loro obiettivo non è quello
di darti ogni funzionalità di cui potresti avere bisogno, ma quello di darti gli strumenti affinchè tu possa implementare qualasiasi cosa
ti passi per la testa. È questo il punto di forza dei framework JavaScript tutti, ed entrambi eccellono in questo.
MooTools ha un approccio più olistico, fornisce gli strumenti per scrivere qualunque cosa, andando oltre il DOM, ma pagando il prezzo di una ripida
curva di apprendimento. L'approccio estensibile e olistico di MooTools ti fornisce tutte le funzionalità di jQuery e oltre, ma jQuery si focalizza su
una eccellente interfaccia per il DOM e comunque non ti impedisce di usare i meccanismi di ereditarietà nativi del JavaScript o di usare un sistema di classi
simile a quello di MooTools, se lo vuoi.
</p>
<p>
Ecco perché dico che entrambi i framework sono ottime scelte.
Il mio sforzo voleva essere quello di evidenziare le differenze <i>filosofiche</i> tra le due librerie ed evidenziarne vantaggi e svantaggi.
Dubito di esser riuscito a tenere la mia simpatia per MooTools completamente sotto controllo, ma spero di esser stato d'aiuto.
A prescindere dal framework che sceglierai, ora conosci sicuramente meglio entrambi. Se hai il lusso del tempo, ti consiglio vivamente di realizzare un sito con
ciascuno. Potrai scrivere il tuo parere su entrambi e magari il tuo punto di vista potrà mettere in luce qualche aspetto che ho trascurato.
</p>
<p>La cronologia di questo documento <a href="http://github.com/anutron/jquery-vs-mootools/tree/master">è consultabile su github</a>.</p>
<p>
<script type="text/javascript" src="http://w.sharethis.com/button/sharethis.js#publisher=c327065b-efa0-4e12-afbc-5717f5cf62f9&type=website&post_services=facebook%2Cdigg%2Cdelicious%2Ctwitter%2Creddit%2Cfriendfeed%2Cmyspace%2Cybuzz%2Cstumbleupon%2Ctechnorati%2Cmixx%2Cblogger%2Cwordpress%2Ctypepad%2Cgoogle_bmarks%2Cwindows_live%2Cfark%2Cbus_exchange%2Cpropeller%2Cnewsvine%2Clinkedin"></script>
</p>
<hr/>
<p class="about">
Chi sono: sono un collaboratore <a href="http://www.mootools.net">MooTools</a> e ho un blog su JavaScript e altro sul mio sito
<a href="http://www.clientcide.com">Clientcide</a>, insieme a <a href="http://www.clientcide.com/js">numerosi plugin
per MooTools</a>. Sono l'autore di
<a href="http://www.amazon.com/gp/product/1430209836?ie=UTF8&tag=clientside-20&link_code=as3&camp=211189&creative=373489&creativeASIN=1430209836">MooTools Essentials</a>
e del <a href="http://www.mootorial.com">tutorial di MooTools</a>. Lavoro in una società nella baia di San Francisco chiamata <a href="http://www.cloudera.com">Cloudera</a>.
Puoi contattarmi <a href="http://www.clientcide.com/shout-out">qui</a>.
</p>
<a name="discussion"></a>
<hr/>
<p class="about" style="color: #700"><strong>Una nota sui commenti</strong>: I commenti sono moderati. Nessun commento verrà pubblicato prima di essere controllato. Commenti non costruttivi (polemici, sgarbati, ecc) non saranno approvati. Allo stesso modo, commenti da "tifoso" non saranno accettati - ad esempio "Il FrameworkX spacca! Sicuramente meglio di FrameworkY!" non è considerato un commento costruttivo.
</p>
<div id="disqus_thread"></div>
<script>
var disqus_url = "http://jqueryvsmootools.com/";
</script>
<script type="text/javascript" src="http://disqus.com/forums/jqueryvsmootools/embed.js"></script>
</div>
<script type="text/javascript">
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
</script>
<script type="text/javascript">
try {
var pageTracker = _gat._getTracker("UA-539314-11");
pageTracker._trackPageview();