Permalink
Find file
Fetching contributors…
Cannot retrieve contributors at this time
1019 lines (907 sloc) 67.3 KB
<!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&ugrave; 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&agrave; ti &egrave; stato imposto un framework, con motivazioni pi&ugrave; o meno discutibili. Se questo &egrave; 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&ograve; 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 &egrave; 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 &egrave; 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&agrave;, ha pi&ugrave; 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&ugrave; i framework presi in considerazione dalla maggior parte delle persone. Non cercher&ograve; di convincere nessuno a passare da un framework a un altro. Entrambi offrono spunti interessanti da cui &egrave; possibile imparare molto. Se vuoi saperne di pi&ugrave; su questo articolo e del perch&eacute; 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&agrave; in JavaScript</a></li>
<li><a href="#self">Autoreferenza</a></li>
</ul>
</li>
<li><a href="#jsfun">MooTools Rende JavaScript Pi&ugrave; Divertente</a></li>
<li><a href="#domfun">jQuery Rende il DOM Pi&ugrave; Divertente</a></li>
<li><a href="#cando">Qualunque Cosa Tu Faccia, Io Posso Farla Meglio</a></li>
<li><a href="#yourway">MooTools Fa Ci&ograve; 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&agrave; in MooTools</a></li>
<li><a href="#extension">Estendere ed Implementare le Classi</a></li>
</ul>
</li>
<li><a href="#conclusion">&Egrave; 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> &amp; <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&igrave;</td>
<td>s&igrave;</td>
</tr>
<tr>
<td>Animazioni</td>
<td>s&igrave;</td>
<td>s&igrave;</td>
</tr>
<tr>
<td>Gestione degli eventi</td>
<td>s&igrave;</td>
<td>s&igrave;</td>
</tr>
<tr>
<td>Selettori CSS3</td>
<td>s&igrave; (un sottoinsieme)</td>
<td>s&igrave; (un sottoinsieme)</td>
</tr>
<tr>
<td>Ajax</td>
<td>s&igrave;</td>
<td>s&igrave;</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&agrave;</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&igrave;</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'&egrave; scritto:
</p>
<blockquote>jQuery &egrave; 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 &egrave; progettato per cambiare il modo in cui si scrive JavaScript.</blockquote>
<p>
...mentre se si va sul sito di MooTools, ecco cosa si trover&agrave; scritto:
</p>
<blockquote>MooTools &egrave; 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&agrave; tutto. Se vuoi sapere cosa ne penso io (e stai leggendo, quindi assumo che tu lo voglia), la domanda non &egrave; 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&agrave; 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 &egrave; 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 &egrave; un <em>framework</em> che cerca di implementare JavaScript <em>come dovrebbe essere</em> (in accordo con gli autori di MooTools). Lo scopo &egrave; quello di implementare una API che sembra JavaScript puro e che lo esalti; non riguarda solamente il DOM. jQuery &egrave; 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&ugrave; piacevole. Accade spesso che il DOM sia l'area in cui la maggior parte delle persone scrive JavaScript, quindi in molti casi jQuery &egrave; tutto quello che serve.
</p>
<p>
Quando si scrive codice con MooTools si ha la sensazione di scrivere JavaScript puro. Se non si &egrave; interessati riguardo al JavaScript come linguaggio, imparare MooTools pu&ograve; sembrare un duro lavoro. Se si &egrave; invece interessati a JavaScript ed in particolare a cosa lo rende interessante, la potenza e l'espressivit&agrave;, 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 &egrave; sicuramente pi&ugrave; facile da imparare. Ha uno stile quasi colloquiale che neanche ti sembrer&agrave; di programmare. Se tutto quello che interessa &egrave; ottenere qualcosa che funzioni velocemente, senza dover imparare JavaScript, jQuery &egrave; probabilmente la scelta migliore. Non che MooTools non aiuti ad ottenere gli stessi risultati, ma ammetto che pu&ograve; essere pi&ugrave; ostico da imparare se se si &egrave; principianti in JavaScript. Inoltre ci sono moltissime risorse che aiutano ad imparare jQuery - almeno, pi&ugrave; 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 &egrave; <i>molto</i>
pi&ugrave; grande (personalmente attribuisco questo fatto a quanto detto prima sulla facilit&agrave; di apprendimento, ma non solo...) e 2) sono
molto pi&ugrave; 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&eacute; si dovrebbe prendere in considerazione anche MooTools
devo prima mostrare cosa fanno i due framework (e come lo fanno).
Alla fine la scelta sar&agrave; 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&ugrave;. Inoltre predispone un modello di ereditariet&agrave; - un qualche esoterico modello chiamato <a href="https://developer.mozilla.org/en/Core_JavaScript_1.5_Guide/Inheritance">ereditariet&agrave; prototipale</a> (ne parler&ograve; pi&ugrave; avanti). Questi blocchi portanti ed il concetto di ereditariet&agrave; 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 &egrave; che il 99% di tutto il JS che c'&egrave; in giro lo vediamo eseguito sui browser ed &egrave; in questo contesto che lo pensiamo. Ossia il linguaggio di programmazione per il browser.
</p>
<p>
Sapere che il browser, il DOM, &egrave; l'area dove la maggior parte delle volte utilizziamo JavaScript ma che quest'ultimo &egrave; anche un linguaggio di programmazione molto robusto ed espressivo aiuter&agrave; 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 &egrave; 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&ograve; sempre continuare ad usare il resto in JavaScript per fare quello che si vuole, ma se si &egrave; focalizzati sul DOM - per cambiare propriet&agrave; CSS, animare elementi, recuperare dei contenuti via Ajax, etc - tutto quello che si vorr&agrave; fare sar&agrave; ottenibile tramite jQuery, pi&ugrave; 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 &egrave; un bene, perch&eacute;, 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&agrave;, si pu&ograve; notare come jQuery non si focalizzi in cose al di fuori del DOM. Questa &egrave; una delle ragioni per cui &egrave; cos&igrave; facile da imparare, ma altres&igrave; limita il modo in cui pu&ograve; aiutare a scrivere JavaScript. Vuol essere niente pi&ugrave; che un solido sistema di programmazione per il DOM. Non prevede ereditariet&agrave; e nemmeno dispone di utilit&agrave; per tutti i tipi nativi del linguaggio JavaScript, ma non ne ha la necessit&agrave;. Se si vogliono fare magie con stringhe, date, espressioni regolari, array e funzioni, &egrave; possibile. Ma aiutare in questo non &egrave; compito di jQuery. JavaScript come linguaggio &egrave; quello che serve. jQuery rende il DOM il tuo ambiente, ma il resto del linguaggio JavaScript &egrave; fuori dalla sua ottica.
</p>
<p>
&Egrave; qui la differenza maggiore rispetto a MooTools. Piuttosto che focalizzarsi esclusivamente sul DOM (comunque, e ci torner&ograve; piu avanti, offre tutte le stesse funzionalit&agrave; 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 &egrave; una delle ragioni per cui &egrave; pi&ugrave; ostico da imparare.
</p>
<a name="inheritance"></a>
<h3>L'Ereditariet&agrave; in JavaScript</h3>
<p>
Il linguaggio di programmazione JavaScript offre alcune cose veramente fantastiche a riguardo. Per i principianti, &egrave; 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. &Egrave; progettato su questo concetto base e molti dei metodi e dei pattern presenti funzionano al meglio quando il codice viene scritto in questo modo. &Egrave; la differenza tra:
</p>
<pre class="js">for (var i = 0; i &lt; 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&agrave;</a> che non &egrave; unico ma piuttosto raro nei linguaggi di programmazione. Invece dell'ereditariet&agrave; a classi (una classe pu&ograve; essere sottoclasse etc) JS vira verso l'ereditariet&agrave; prototipale. Questo significa che gli oggetti ereditano direttamente da altri oggetti. Se si referenzia una propriet&agrave; in un oggetto che eredita da un altro oggetto, il linguaggio ispeziona l'oggetto figlio per quella propriet&agrave; e, se non la trova, la cerca nel padre. Questo &egrave; 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 &egrave; una propriet&agrave; dell'array che viene dichiarato ([1,2,3]), ma &egrave; una propriet&agrave; 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 &egrave; in memoria per ogni array dichiarato; &egrave; in memoria soltanto per il prototipo degli array. In due parole: efficienza e potenza. (nota: l'alias utilizzato in MooTools per forEach &egrave; each)
</p>
<a name="self"></a>
<h3>Autoreferenza</h3>
<p>
In JavaScript esiste una keyword speciale: "this". &Egrave; difficile per me in poche parole definirla ma, di default, "this" &egrave; 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'&egrave; 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 &egrave; 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'&egrave; 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 &egrave; 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 &egrave; il "this" dentro al metodo <em>logInventory</em>) al metodo che passiamo all'array in modo che ci si possa riferire alla propriet&agrave; 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&agrave; che JavaScript ha da offrire - ereditariet&agrave;, auto referenza e binding, ed efficienti propriet&agrave; prototipali. La brutta notizia riguarda il fatto che JavaScript puro non rende queste cose potenti molto usabili o accessibili, ed &egrave; 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, &egrave; una buona cosa - una cosa potente. Capire come questi patterns siano preziosi e come usarli correttamente richiede uno sforzo, ma la cosa positiva &egrave; che il codice che si scrive &egrave; molto pi&ugrave; riusabile e facile da mantenere. Andr&ograve; nei dettagli a riguardo tra un minuto.
</p>
<a name="jsfun"></a>
<h2>MooTools Rende JavaScipt Pi&ugrave; 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 &egrave; un'estensione del linguaggio JavaScript. MooTools prova a rendere il JavaScript cos&igrave; com'&egrave; 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 &egrave; 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&ugrave; classico modello di ereditariet&agrave; 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 &egrave; cos&igrave;</a>. Quello che fa <em>Class</em> &egrave; rendere il modello di ereditariet&agrave; prototipale del JavaScript pi&ugrave; facile ed accessibile e qualcosa da cui prendere vantaggio. Da notare che questi concetti non sono unici in MooTools (altri frameworks offrono funzionalit&agrave; similari), ma non sono presenti in jQuery. Quest'ultimo non offre un sistema di ereditariet&agrave; n&eacute; offre estensioni per gli oggetti nativi (Function, String, etc). Sia chiaro, non &egrave; 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&ugrave; divertente, jQuery mira a rendere il DOM pi&ugrave; 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&ugrave; Divertente</h2>
<p>
Ed &egrave; per questo che jQuery &egrave; pi&ugrave; accessibile. Non presuppone che si impari JavaScript in lungo ed in largo. Non mette di fronte l'ereditariet&agrave; 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 &egrave; il primo esempio che ci si trova davanti:
</p>
<pre class="js">window.onload = function() {
alert("benvenuto");
}</pre>
<p>e qui c'&egrave; 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&ograve; 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 &egrave; alle prime armi con la programmazione, o si vuol solamente qualcosa che funzioni nel proprio sito senza approfondire il linguaggio JavaScript, jQuery sicuramente risulter&agrave; molto pi&ugrave; semplice ed "amichevole".
</p>
<p>
D'altra parte, se si vuol veramente imparare JavaScript, MooTools &egrave; 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 &egrave; 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&ograve; fare, c'&egrave; sempre una stessa funzionalit&agrave; in MooTools. Riguardo quello che MooTools pu&ograve; fare, non c'&egrave; modo a volte di emularle in codice jQuery dato che quest'ultimo si focalizza solamente sul DOM. MooTools ha pi&ugrave; funzionalit&agrave; di jQuery, ma non c'&egrave; niente in jQuery che permetta di emularle. Ad esempio, jQuery non fornisce nessun sistema di ereditariet&agrave;, ma non c'&egrave; problema. Si potrebbe, se si vuole, utilizzare il modulo <em>Class</em> di MooTools in aggiunta a jQuery. C'&egrave; inoltre un <a href="http://code.google.com/p/jquery-inheritance/updates/list">plugin che mette a disposizione l'ereditariet&agrave; in jQuery</a> (non l'ho utilizzato, ma penso offra pi&ugrave; o meno lo stesso tipo di funzionalit&agrave;)
</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&ugrave; 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&agrave;:
</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 &egrave; pi&ugrave; esplicita, ma anche molto verbosa. &Egrave; 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 &egrave; pi&ugrave; 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 &egrave; pi&ugrave; leggibile, ma &egrave; un'osservazione prettamente personale.
</p>
<p>
Devo dire inoltre che qualche volta jQuery pu&ograve; 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&agrave; con MooTools, per me leggere MooTools &egrave; pi&ugrave; 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&ugrave; coerenti e consistenti.
</p>
<a name="yourway"></a>
<h2>MooTools Fa Ci&ograve; Che Vuoi Come Vuoi</h2>
<p>
E se ti piace la sintassi jQuery? Un modo per illustrare il potere di MooTools &egrave; 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&igrave;:</p>
<pre class="js">Element.implement({
hover : function(enter,leave){
return this.addEvents({ mouseenter : enter, mouseleave : leave });
}
});
//e quindi lo si potr&agrave; 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&agrave; significa che si pu&ograve; implementare praticamente qualsiasi cosa si voglia. Questo &egrave; qualcosa che jQuery non pu&ograve; fare. MooTools pu&ograve; simulare jQuery volendo, ma jQuery non pu&ograve; mimare MooTools. Se si vogliono scrivere classi oppure estendere i prototipi nativi o fare qualcosa che MooTools pu&ograve; fare, avendo adottato jQuery bisogner&agrave; 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'&egrave; 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 &egrave; 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&ograve; riguarda solo me dato che jQuery viene utilizzato da tantissime persone (che sono contente di usarlo), quindi anche questa &egrave; 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 &egrave; pi&ugrave; verboso, ma anche pi&ugrave; 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 &egrave; 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 &egrave; una brutta abitudine. &Egrave;' molto meglio incapsulare la logica in moduli riusabili.
</p>
<a name="reuse"></a>
<h2>Riutilizzo del codice con jQuery</h2>
<p>
&Egrave; 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 &egrave; 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&agrave; ripetere la stessa logica ogni volta che si trover&agrave; 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 &egrave; migliore per due ragioni importantissime:
</p>
<ol>
<li>
Se in futuro ci sar&agrave; 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&agrave; pi&ugrave; facile sistemare i bugs, aggiornare i frameworks, aggiungere features, o alterare funzionalit&agrave;.
</li>
<li>
La seconda: c'&egrave; meno codice. Riusando lo stesso metodo pi&ugrave; volte, non bisogner&agrave; ripetersi e questo &egrave; 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&ugrave; rifinito per scrivere "widget" riusabili come questi. Piuttosto che incoraggiare a mettere tutto dentro funzioni come nell'esempio qui sopra (che &egrave; 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" &egrave; 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&igrave;:
</p>
<pre class="js">$('#faq').faq();</pre>
<p>
Guardando all'esempio qui sopra, non c'&egrave; molta differenza tra dichiarare la nostra funzione <i>faq</i> in questo modo e dichiararla come una funzione vera e propria. Non &egrave; 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 &egrave; il contesto corrente dell'elemento nella concatenazione jQuery in quel momento. Utilizzando questo pattern per i plugins si potr&agrave; essere in grado di renderli parte integrante di jQuery, ma a parte quello, un plugin &egrave; 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 &egrave; 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 &egrave; possibile scrivere plugins jQuery pi&ugrave; complessi con i metodi e gli stati. Questo tipo di pattern &egrave; 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&agrave; all'oggetto jQuery (i.e. <em>$.ui.tabs</em>). C'&egrave; un modo semplice per invocare questo oggetto (<em>$(selector).tabs()</em>) cosicch&eacute; 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 &egrave; forzati a chiamare ancora il selettore per invocarci metodi. Invece di chiamare <em>myTabInstance.add(url, label, index)</em> bisogner&agrave; 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 &egrave; focalizzato sui core di MooTools e jQuery, e mentre il sistema jQuery UI fornisce questa funzionalit&agrave;, non &egrave; qualcosa che &egrave; 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 &egrave; 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> &egrave; gi&agrave; 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&ograve; solamente eseguire <i>" non pi&ugrave; spazi alla fine! ".trim()</i> ed ottenere <i>"non pi&ugrave; spazi alla fine!"</i>. Alcuni direbbero che implementare propriet&agrave; direttamente nei prototipi nativi &egrave; inappropriato. &Egrave; 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&ograve; dire che &egrave; lo stesso problema che si incontra con il namespace globale <em>window</em>. Comunque &egrave; cos&igrave; che funziona JavaScript. &Egrave; 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&agrave;, 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 &egrave; disponibile per il framework adottato, sarebbe pi&ugrave; 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 &egrave; capito come funziona JavaScript e si &egrave; realizzato il potere dell'estensione dei tipi nativi, si scoprir&agrave; 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 &egrave; &quot;sporco&quot;, io dico che &egrave; proprio questa la feature principale di JavaScript. &Egrave; una sua caratteristica architetturale. Aggiungendo metodi ai tipi nativi il codice risulter&agrave; 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&agrave; 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&ograve; 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 &egrave; 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&ugrave; elementi in una singola volta.
</p>
<p>
La chiave qui, ed &egrave; il cuore del framework MooTools, &egrave; il guidare a programmare ci&ograve; che si vuole. Se una funzionalit&agrave; non &egrave; presente nel core, lo si pu&ograve; estendere aggiungendola. L'obiettivo del core non &egrave; provvedere ad ogni singola funzionalit&agrave; possibile ed immaginabile, ma &egrave; mettere a disposizione gli strumenti per scrivere ci&ograve; che si vuole. Una grossa parte riguarda la facilit&agrave; con la quale si possono estendere i tipi nativi, traendo vantaggio dall'ereditariet&agrave; prototipale. Si possono fare tutte queste cose in JavaScript nativo, ma MooTools rende il tutto pi&ugrave; semplice e pi&ugrave; piacevole.
</p>
<a name="mooinheritance"></a>
<h3>L'Ereditariet&agrave; in MooTools</h3>
<p>
Nonostante il suo nome, in MooTools la funzione <em>Class</em> non &egrave; 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&agrave; <em>Class</em> riguarda sempre oggetti ed ereditariet&agrave; prototipale. (Sfortunatamente la parola "class"
&egrave; quella che meglio descrive queste cose, quindi nell'articolo quando parlo di "classi" faccio riferimento a funzioni che ritornano oggetti - che chiamer&ograve;
"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&agrave; e metodi come "isAlive" e "eat") l'oggetto diventa il prototipo
di ogni istanza di quella classe. Dopo aver creato la classe, &egrave; 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&agrave; dell'oggetto definito al momento della creazione della class <em>Human</em>.
Ma la cosa importante &egrave; che <em>bob</em> ha queste propriet&agrave; per ereditariet&agrave;. 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&agrave;,
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&ograve;
pu&ograve; sembrare sbagliato; non vogliamo che tutti gli umani acquisiscano energia ogni volta che <i>bob</i> mangia. La cosa importante da capire &egrave;
che appena assegniamo un valore all'energia di <i>bob</i>, assegniamo a <i>bob</i> un valore proprio, e non guardiamo pi&ugrave; al valore del prototipo.
Perci&ograve; la prima volta che <i>bob</i> manger&agrave;, acquisir&agrave; 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&agrave; di <em>bob</em> sono unicamente suoi; infatti queste due propriet&agrave; vengono ad esso assegnate durante l'inizializzazione
della classe, nel metodo <i>initialize</i>.
</p>
<p>
Tutto questo comportamento pu&ograve; sembrare un po' strano, ma il suo punto di forza sta nel fatto che possiamo definire funzionalit&agrave; per un certo modello e
creare istanze di quel modello ogni volta che ne abbiamo bisogno. Ogni istanza manterr&agrave; il proprio stato. Dunque se creiamo un'altra
istanza, ciascuna sar&agrave; indipendente dalle altre, ma erediter&agrave; 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&agrave; 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, &egrave; una singola funzione),
praticamente realizzando un "fork", oppure lo invochiamo e aggiungiamo successivamente le nuove funzionalit&agrave; 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" &egrave 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'&egrave; 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 &egrave; un problema in quanto l'effetto sicuramente partir&agrave; prima che la nostra richiesta ajax finisca di caricare. Non c'&egrave;
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&agrave; <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&agrave; 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&ograve; vedere come abbiamo aggiunto molte funzionalit&agrave; in una sottoclasse.
Questa sottoclasse ha alcune propriet&agrave; 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 &egrave; 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&agrave;
(come <em>energy</em>, pari a 100 anzich&eacute; 1), e definire nuove funzionalit&agrave;. 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, &egrave; possibile anche definire una classe che
viene miscelata ad altre classi affinch&eacute; possa mettere a
disposizione di queste le sue propriet&agrave;.
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&agrave; 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&agrave; di <em>Warrior</em> (guerriero) in questo modo:
</p>
<pre class="js">var Ninja = new Class({
Extends: Human,
Implements: Warrior, //pu&ograve; essere un array se vogliamo implementare pi&ugrave; 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> &egrave; 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 &egrave; stato
necessario per definirle. Sono simili tra loro, perch&eacute; entrambi umani con abilit&agrave; da guerriero,
ma sono differenti in quanto un samurai sar&agrave; sempre buono ("good"), mentre un ninja pu&ograve; 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&eacute; &egrave; 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 &egrave; 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 &egrave; 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&ugrave; 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&ograve;! &Egrave; un sacco di codice. Anche se togliessimo tutti i commenti, sarebbero ancora due dozzine di linee.
Ho gi&agrave; mostrato come sia possibile realizzare questo plugin con pi&ugrave; o meno la stessa quantit&agrave; di codice
della versione jQuery. Allora perch&eacute; questa versione &egrave; cos&igrave; tanto lunga? Beh, l'abbiamo resa molto pi&ugrave; 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&agrave; 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&ugrave; questo problema con MooTools:
</p>
<pre class="js">FAQ.Ajax = new Class({
//questa classe eredita le propriet&agrave; della classe FAQ
Extends: FAQ,
//aggiungiamo anche un'altra opzione a quelle di default.
//questa &agrave; l'url, alla quale aggiungeremo l'indice del
//termine; veramente potremmo fare qualcosa di pi&ugrave; robusto,
//ma come esempio va bene cos&igrave;
options: {
url: null;
},
//memorizzeremo i risultati delle chiamate ajax, cos&igrave; se una sezione verr&agrave;
//aperta due volte non avremo bisogno di interrogare nuovamente il server
indexesLoaded: [],
toggle: function(index){
//se abbiamo gi&agrave; 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&agrave; (ajax) e poco altro.
Questa estensibilit&agrave; rende possibile la creazione di famiglie di plugin che offrono diverse
sfumature di medesime funzionalit&agrave;. Ci&ograve; 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&eacute;, 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,
&egrave; possibile estenderli facilmente aggiungendo quello che serve.
</p>
<p>
Come ho illustrato prima, &egrave; possibile scrivere widget complessi con jQuery, con metodi e stato.
Gran parte del codice scritto facendo ci&ograve; &egrave; JavaScipt puro quando c'&egrave; 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'&egrave; un sistema con stato per fare cose di questo tipo, a meno che non lo si scriva appositamente.
</p>
<a name="conclusion"></a>
<h2>&Egrave; ora di decidere</h2>
<p>
jQuery mira all'espressivit&agrave;, alla scrittura rapida e veloce di codice e al DOM, mentre MooTools mira ad estendibilit&agrave;, ereditariet&agrave;,
leggibilit&agrave;, riuso del codice e mantenibilit&agrave;.
Puoi vederli come due punti opposti di una scala. Da una parte jQuery &egrave; qualcosa che ti permette di iniziare con semplicit&agrave; ed avere subito il risultato,
ma (per mia esperienza) pu&ograve; trasformarsi in codice difficile da riutilizzare e mantenere (o meglio, questa &egrave; una tua responsabilit&agrave;, non
un problema di jQuery in s&egrave;). Dall'altra parte MooTools necessita di pi&ugrave; tempo per imparare e richiede pi&ugrave; codice prima
che tu possa vedere i risultati del tuo lavoro, ma successivamente quello stesso codice sar&agrave; pi&ugrave; riusabile e pi&ugrave; mantenibile.
</p>
<p>
N&eacute; il nucleo <i>(core)</i> di MooTools n&eacute; quello di jQuery forniscono tutte le funzionalit&agrave; immaginabili. Entrambi i framework mantengono
un nucleo piuttosto snello, lasciando a te e agli altri sviluppatori la possibilit&agrave; di creare plugin ed estensioni. Il loro obiettivo non &egrave; quello
di darti ogni funzionalit&agrave; di cui potresti avere bisogno, ma quello di darti gli strumenti affinch&egrave; tu possa implementare qualasiasi cosa
ti passi per la testa. &Egrave; questo il punto di forza dei framework JavaScript tutti, ed entrambi eccellono in questo.
MooTools ha un approccio pi&ugrave; 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&agrave; 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&agrave; nativi del JavaScript o di usare un sistema di classi
simile a quello di MooTools, se lo vuoi.
</p>
<p>
Ecco perch&eacute; 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&agrave; 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">&egrave; consultabile su github</a>.</p>
<p>
<script type="text/javascript" src="http://w.sharethis.com/button/sharethis.js#publisher=c327065b-efa0-4e12-afbc-5717f5cf62f9&amp;type=website&amp;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&agrave; 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&agrave; 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 &egrave; 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();
} catch(err) {}</script>
<script type="text/javascript">
//<![CDATA[
(function() {
var links = document.getElementsByTagName('a');
var query = '?';
for(var i = 0; i < links.length; i++) {
if(links[i].href.indexOf('#disqus_thread') >= 0) {
query += 'url' + i + '=' + encodeURIComponent(links[i].href) + '&';
}
}
document.write('<script charset="utf-8" type="text/javascript" src="http://disqus.com/forums/jqueryvsmootools/get_num_replies.js' + query + '"></' + 'script>');
})();
//]]>
</script>
</body>
</html>