Prototype es una librería JavaScript Orientada a Objetos (escrita por Sam Stephenson y amigos) que hace a JavaScript divertido. Esto lo dice su sitio de todas las formas. Aquellos que estén familiarizados con el último y mayor marco de aplicaciones Open Source, Rails, pueden reconocer a Prototype como la espina dorsal del asistente JavaScript de Rails. Sin embargo, Prototype se puede utilizar independientemente de Rails para ayudar a la codificación de muchas aplicaciones de la Web 2.0.
Personalmente, yo tengo un juicio aparte en el conjunto de cosas divertidas del JavaScript, pero Protoype es una librería realmente buena que, aunque la situación ha estado mejorando últimamente, ha tenido escasa documentación. Este artículo proporciona un viaje relámpago pero completo de la librería. A lo que apuntamos con esto, es proporcionar ejemplos y recursos para poder empezar a incluir a Prototype en sus proyectos DOM Scripting.
Primero, examinaremos los componentes básicos de Prototype: Las funciones $, Las adiciones a los Strings, Números, Arrays y Funciones de objetos. En otro artículo veremos sus bondades en el manejo de formularios y las funciones de DOM, seguiremos observando a los ayudantes de Ajax. Y finalmente, terminaremos con una breve discusión de otros proyectos interesantes que están basados en Prototype.
Me gustaría notar que la versión estable de Prototype al momento de escribir este artículo es la 1.4.0. Tengo el presentimiento, que la librería se actualizará muy rápidamente, en respuesta al ciclo de desarrollo veloz de Rails, entonces las cosas cambiarán. Finalmente, lo que malogra la nota es que en estos momentos, es que Prototype sólo soporta a los navegadores más recientes. Puede visitar el sitio de Prototype, para más información sobre el soporte de navegadores.
Primeros Pasos
La anterior versión de Prototype puede ser descargada del sitio oficial de prototype. Simplemente descargue prototype.js y enlácelo en sus páginas con la etiqueta <script>.
<script type="text/JavaScript" src="path/to/prototype.js"></script>
Si esta utilizando Rails, no necesita descargar Prototype: La librería viene incluido en la distribución. Usted puede incluirlo en sus páginas poniendo dentro de las etiquetas <head>:
<%= javascript_include_tag 'prototype' %>
Ahora, vamos al fondo del tema!
Pequeñas ayudas de Prototype
Una de las cosas realmente agradables sobre la utilización de Prototype son las sencillas funciones de ayuda que proporciona para las tareas comunes de scripting. Las funciones $ ya han conseguido algo de atención. Denle uno o vario elementos ID y le devolverán referencias a ellos:
// reference to the element with the ID 'nav'
$("nav")
// an array of element references
$("img1", "img2", "img3")
Es como una superposición de document.getElementById y es asombroso cuanto conviene esta codificación cuando usted la utiliza.
Otra función increíblemente útil es document.getElementsByClassName, que hace lo que dice la lata: Toma un nombre de clase CSS y devuelve una lista de todos los elementos con dicha clase:
// todos los elementos con la clase 'navlink'
document.getElementsByClassName("navlink")
// todos los elementos con la clase navlink y detrás el elemento con ID 'nav'
document.getElementByClassName("navlink", $("nav"))
Por cierto, cuando este artículo fue escrito, la versión 1.5.0_rc0 de Prototye ganó la poderosa función $$, que permite seleccionar elementos usando una sintaxis estándar del selector CSS:
// un array de todos los elementos input detras de 'commentform'
$$("#commentform input")
// un array de todos los links con la clase 'external'
$$("a.external")
Por favor, tenga presente que, a la hora de escribir, a menos que usted descargue la versión más reciente de Prototype, esta función no estará disponible para usted.
$F toma un ID y devuelve el valor de cualquier campo de formulario, por ejemplo, un menú select como este:
<select name="country" id="country">
<option selected="selected" value="UK">United Kingdom</option>
<option value="FR">France</option>
...
</select>
$F('country') // 'UK'
Haciendo que JavaScript aspire menos
Oops, he robado la etiqueta de otra librería JavaScript. Los desarrolladores de la librería JavaScript no pueden dejar de intentar que JavaScript se parezca a otra lengua. Los individuos de Mochikit quisieran que JavaScript fuera como Python, incontables programadores han intentado hacer a JavaScript como Java y ahora, los intentos de Prototype para hacerlo a gusto de Ruby. Por tanto, Prototype extiende la base de JavaScript, que puede (si usted elige utilizarlo) tener un efecto dramático en su acercamiento a la codificación JavaScript. Dependiendo de su experiencia y de la manera en que proyecta sus trabajos, la librería puede, o no, ser de su ayuda.
OO la manera Ruby(ista): Class.create y Object.extend
El método Class.create permite definir clases de un modo muy parecido a Ruby, aunque sea puramente estético es esencial para inicializar el método que define el constructor.
var DOMTable = Class.create();
DOMTable.prototype = {
initialize : function(el) {
this.el = el;
},
...
}
Sin embargo, mucho más potente es el método simple pero eficaz de Object.extend. Todo lo que lo hace es copiar las propiedades y métodos de un objeto a otro objeto, pero sus aplicaciones son muchas. Aquí un test rápido:
// make a (shallow) copy of obj1
var obj2 = Object.extend({}, obj1);
var options = {
method : "post",
args :
<BR>}; </FONT></P>
<P><FONT color=#993300>
merges in the given options object to the default options object opciones implícitas <BR>Object.extend(options, { <BR>args : "data=454", <BR>onComplete : function() { alert("done!"); } <BR>}); </FONT></P>
<P><FONT color=#993300>options.method "post" <BR>options.args
"ata=454" <BR>options.onComplete function() { alert("done!"); } </FONT></P>
<P>Esto es lo más es usado para "<EM>mezclar</EM>" métodos de un objeto con otro. Por ejemplo, usted podría crear un juego de funciones que hacen seguros los elementos de DOM Sortable: </P>
<P><FONT color=#993300>var Sortable = { <BR>sortBy : function(func) { <BR>... <BR>}, <BR>sortByReversed : function(func) { <BR>... <BR>}, <BR>reset : function() { <BR>... <BR>} <BR>};</FONT> </P>
<P>Luego, si queremos hacer nuestro <FONT color=#993300>DOMTable</FONT> desde Sortable, podríamos mezclar en estos métodos al objeto de <FONT color=#993300>DOMTable</FONT>: </P>
<P><FONT color=#993300>var myTable = new DOMTable("table-id"); <BR>Object.extend(myTable, Sortable);</FONT> </P>
<P>Ahora podemos llamar estos elementos en una tabla. </P>
<P><FONT color=#993300>
sort the table using the given function <BR>myTable.sortBy(function (itemA, itemB) { ... }); </FONT></P>
<P><STRONG><FONT color=#000000 size=2>Función Binding</FONT></STRONG> </P>
<P>Prototype también añade a la función objeto dos métodos realmente útiles: <FONT color=#993300>bind</FONT> y <FONT color=#993300>bindAsEventListener</FONT>. Estos son usados muchas veces para atar una función a un objeto particular de modo que la palabra clave apunte a ese objeto. Esto es increíblemente útil cuando usted está fijando funciones. Imagínese que usted intenta algo como esto: </P>
<P><FONT color=#993300>var myObject = new Object(); <BR>myObject.message = "Hello!"; <BR>myObject.eventHandler = function() { <BR>alert(this.message); <BR>} </FONT></P>
<P><FONT color=#993300>$("mydiv").onmouseover = myObject.eventHandler;</FONT> </P>
<P>Tradicionalmente, usted conseguiría un error, porque, cuando el evento llama a la función handler, esta se refiere al elemento mydiv, no a myObject, entonces this.message es indefinido. Usted puede solucionar este problema con: </P>
<P><FONT color=#993300>$("mydiv").onmouseover = myObject.eventHandler.bind(myObject);</FONT> </P>
<P>Ahora todo trabaja muy bien, porque la palabra clave está limitada a myObject. Siguiendo esto, el bindAsEventListener hace lo mismo, aunque pasa el objeto del evento a través de su función de una manera compatible de cross-browser, así que usted no tiene ninguna necesidad de preocuparse del window.event en IE. Trate esto: </P>
<P><FONT color=#993300>myObject.eventHandler = function(event) { <BR>alert(event.srcElement.nodeName); <BR>} </FONT></P>
<P><FONT color=#993300>$("mydiv").onmouseover = myObject.eventHandler.bindAsEventListener(myObject);</FONT> </P>
<P>Ahora nuestra función de eventHandler tiene el acceso al objeto del evento. Mayores detalles de estos dos métodos están disponibles en <A href="http://www.brockman.se/writing/method-references.html.utf8∞" target=_blank><STRONG><FONT color=#dc7e1e>el sitio de su creador</FONT></STRONG></A>. </P>
<P><FONT color=#000000 size=2><STRONG>Nuevos Métodos de String y Números</STRONG></FONT> </P>
<P>Prototype ha añadido un enorme número de métodos útiles al construir objetos String. Aquí tiene una mirada rápida de lo mejor. </P>
<P><FONT color=#993300> "backgroundColor" <BR>"background-color".camelize()</FONT> </P>
<P><FONT color=#993300>camelize</FONT> devuelve strings que uno puede trabajar con propiedades CSS. </P>
<P><FONT color=#993300>
"I am a piece of HTML" <BR>"I am a piece of <strong>HTML</strong>".striptTags() </FONT></P>
<P><FONT color=#993300> {a : 10, b: "thing"} <BR>"a=10&b=thing".toQueryParams()</FONT> </P>
<P>También Prototype añade un gran método para Numerar. ¡Diga adiós a los loops!.</P>
<P><FONT color=#993300>
alerts "1", "2", "3" ... "50" <BR>50.times(function(n) { <BR>alert(n); <BR>}};</FONT> </P>
<P>Aquí, el método de “times” toma una función que llamará a un número dado de veces y pasa en la corriente interacción de los números como un argumento. Este empleo de una función de interacción es común usando Enumerable, del cual hablamos a continuación. </P>
<P><FONT color=#000000 size=2><STRONG>Interacción a la manera de Ruby: Enumerable y Hash</STRONG></FONT> </P>
<P>Unas de las gemas ocultas de Prototype es <FONT color=#993300>Enumerable</FONT> y el objeto <FONT color=#993300>Hash</FONT>, que han sido usurpados directamente de ruby. Si usted no esta familiarizado con ruby, no se preocupe. Lo explicaré todo aquí. </P>
<P>Comenzaremos con <FONT color=#993300>Enumerable</FONT>. En breve cuando sumamos <FONT color=#993300>Enumerable</FONT> a un objeto que usa <FONT color=#993300>Object.extend</FONT>, le da al objeto en cuestión, muchas funciones realmente útiles para trabajar con sus propiedades. <FONT color=#993300>Enumerable</FONT> ha sido agregado Prototype Arrays, entonces cualquier array tiene estos métodos nuevos. Aquí están unos ejemplos de lo que usted puede hacer con los nuevos arrays "enumerados":</P>
<P><FONT color=#993300> alerts "a is at 0" then "b is at 1" then "c is at 2" <BR>["a", "b", "c"].each(function(item, index) { <BR>alert(item + " is at " + index); <BR>}); </FONT></P>
<P><FONT color=#993300>
[80,50] <BR>[1, 80, 3, 50].select(function(item) { <BR>return (item > 20); <BR>});</FONT> </P>
<P><FONT color=#993300>Select</FONT> crea un nuevo Array que contiene sólo los elementos que hacen que la función devuelva true. </P>
<P><FONT color=#993300> ["A", "B", "C"] <BR>["a", "b", "c"].invoke("toUpperCase");</FONT> </P>
<P><FONT color=#993300>Invoque</FONT> llamadas al especificar el método de cada elemento del Array y devuelve el arrray resultante. </P>
<P><FONT color=#993300>
["cat", "rat"] <BR>["cat", "dog", "rat", "mouse",].grep(/at/);</FONT> </P>
<P><FONT color=#993300>Grep</FONT> devuelve todos los elementos que emparejan la expresión regular dada. </P>
<P>Enumerables ofrece un inmenso número de funciones increíblemente poderosas que pueden hacer el desarrollo, del tedioso DOM scripting, en una tris. Por ello, sugiero que usted de una buena mirada a los métodos de <FONT color=#993300>Enumerable</FONT> en los <A href="http://www.sergiopereira.com/articles/prototype.js.html#Reference.Enumerable%3Cbr%20/%3E∞" target=_blank><STRONG><FONT color=#dc7e1e>útiles apuntes de desarrollador, de Sergio Pereira</FONT></STRONG></A>. </P>
<P>Hay un pequeño problema aquí, aunque en JavaScript, usted puede encontrar por casualidad muchos tipos de objetos que, a efectos prácticos, actúan como arrays, pero no son objetos de <FONT color=#993300>arrays</FONT>. Los objetos como DOM <FONT color=#993300>NodeLists</FONT> y argumentos de función no tendrán a Enumerable disponible automáticamente. Esto es fácil de rectificar, aunque; para agregar las funciones Enumerables a cualquier objeto parecido a un Array debe usar <FONT color=#993300>$A</FONT>: </P>
<P><FONT color=#993300> add Enumerable to childNodes <BR>var children = $A($("mydiv").childNodes); </FONT></P>
<P><FONT color=#993300>
sets class="highlighted" for all child nodes of "mydiv" <BR>children.each(function(child) { <BR>child.setAttribute("class", "highlighted"); <BR>});</FONT> </P>
<P>Para crear un <FONT color=#993300>Hash</FONT>, llame a la función mágica <FONT color=#993300>$H</FONT> en cualquier objeto. Esto gira todas las propiedades del objeto en un juego de pares de valor clave con <FONT color=#993300>Enumerable</FONT>. Vamos a tomar <FONT color=#993300>Hash</FONT> para dar una vuelta: </P>
<P><FONT color=#993300> create a hash by feeding an object to $H <BR>var contact = $H({ <BR>name : "Dan Webb", <BR>email : "dan@danwebb.net", <BR>address : "None of your Business, London", <BR>postcode : "a111111" <BR>}); </FONT></P>
<P><FONT color=#993300>
["name", "email", "address", "postcode"] <BR>contact.keys() <BR> ["Dan Webb", "dan@danwebb.net","None of your Business, London", "a111111"] <BR>contact.values() <BR>
"name=Dan Webb&email=..." <BR>contact.toQueryString()</FONT> </P>
<P>Hash extiende a <FONT color=#993300>Enumerable</FONT>, entonces todos aquellos métodos útiles están también disponibles. </P>
<P><FONT color=#993300> alerts "name contains Dan Webb" and so on <BR>contact.each(function(item) { <BR>alert(item.key + " contains " + item.value); <BR>});</FONT> </P>
<P>¡Al principio, si usted no es un Rubyista, <FONT color=#993300>Enumerable</FONT> y el <FONT color=#993300>Hash</FONT> pueden parecer un poco tediosos; pero puedo asegurarle, una vez que usted comience a usarlos, usted se preguntará por qué alguna vez se molestó en conseguir un RSI que escriba todos aquellos loops! Cuando usa a uno o varios de ellos juntos, comprenderá el poder masivo de estos nuevos métodos. Usted puede leer sobre <FONT color=#993300>Enumerable</FONT> y el <FONT color=#993300>Hash</FONT> más detalladamente en <A href="
http://encytemedia.com/blog/articles/2005/12/07/prototype-meets-ruby-a-look-at-enumerable-array-and-hash%3Cbr%20/%3E∞" target=_blank><STRONG><FONT color=#dc7e1e>Encyte Media</FONT></STRONG></A>. </P>
<P>El objeto <FONT color=#993300>Event</FONT> ayuda a proveer, lo que a muchos, es el Santo Grial del JavaScript: Simple, Cross-browser event handling: </P>
<P><FONT color=#993300>function eventHandlerFunction(e) { <BR>
the element that triggered the event <BR>var element = Event.element(e); <BR> gets the mouse position <BR>var mouseX = Event.pointerX(e), <BR>mouseY = Event.pointerY(e); <BR>
stop default behaviour and event propagation <BR>Event.stop(e); <BR>} </FONT></P>
<P><FONT color=#993300> register eventHandlerFunction to the onclick of myObject <BR>Event.observe(myObject, "click", eventHandlerFunction, false); </FONT></P>
<P><FONT color=#993300>
removes the event handler <BR>Event.stopObserving(myObject, "click", eventHandlerFunction, false); </FONT></P>
<P>De un modo bastante agradable, Prototype trata de evitar aquellos escapes de memoria indeseados en IE automáticamente, quitando a cada observador cuando la página se descarga. </P>
<P>En mi opinión, la solución en este momento es un sub-desarrollo del manejo del evento, por lo que podría valer la pena pensar en usar algo un poco más rico como <A href="http://dean.edwards.name/my/events.js∞" target=_blank><STRONG><FONT color=#dc7e1e>addEvent del Decano Edwards</FONT></STRONG></A>, por el momento.</P>
<P></P>
<DIV id=tags><A id=post-category title=dhtml href="http://www.baluart.net/categoria/dhtml"><STRONG><FONT∞ color=#333333></FONT></STRONG></A> </DIV>""