aitor.name
Prototype.jsBreve introducción
aitor.name
Historia
● Creado en 2005 por Sam Stephenson como parte del soporte AJAX de Ruby on Rails
● Proyecto externo a Rails pero muy vinculado a él
● Muy usada por developers Rails
aitor.name
Uso real
aitor.name
Principales funcionalidades
● Manipulación e inspección del DOM● Gestión de eventos● Extensiones a Javascript● AJAX de alto nivel
aitor.name
DOM > Extensión
● Principal característica diferenciadora con otros frameworks
● Añade métodos (funciones) extra a los nodos del DOM
● Es automágica en navegadores que soportan modificar el “prototype” de objetos nativos
| var obj = document.| getElementById( “id”);|| obj.addClassName( “clase”);
aitor.name
DOM > Acceso a los elementos
● $(id) → document.getElementById()
● También extiende elementos
| // viejos navegadores (IE6) | var e = document.| getElementById( “flash”);|| e.hide(); // FAIL| $( e).hide(); // WIN
| $( “flash”).hide();
aitor.name
DOM > Acceso a los elementos
● $$(sel) → document.querySelectorAll()
| // devuelve array de elementos| var links = $$( “a.ugly”);|| for( link in links) {| link.remove();| }
aitor.name
| // setStyle, getStyle, hide, toggle,| // getDimensions ...
DOM > Resumen de funcionalidad
● Navegación
● Modificación
● Estilos
| // descendants, siblings, ancestors,| // previousSiblings ...
| // absolutize, addClassName, remove,| // insert, update ...
aitor.name
DOM > Extensiones propias
● Funciones globales (nada nuevo)
| // $$() simplificado| function $$0( selector) {| return ( $$( selector))[ 0];| }|| $$0( “#banner img.p0rn”).show();
aitor.name
DOM > Extensiones propias
● Extensión del DOM
| Element.addMethods( {| bordea: function( element, color) {| element.setStyle( {| border: "10px solid " + color| });| return element; // para encadenar| }| });|| $( “id”).bordea( “pink”).show();
aitor.name
Eventos
● La gestión de eventos es lo más doloroso en el soporte de múltiples navegadores
● Resumen: todo el mundo lo hace como manda la W3C, e IE lo hace de otra forma totalmente diferente (+ pierde memoria en algunos casos)
● Otros pequeños detalles entre navegadores
aitor.name
Eventos > Registro
● Event.observe() es la base de la gestión de eventos
| function activar( event) {| var element = event.element();| element.addClassName( “activa”);| }|| $( “bocina”).observe( “click”,| activar| );
aitor.name
Eventos > Desregistro
● Event.stopObserving() y sus múltiples personalidades
| // un evento/handler concreto| $( “buy”).stopObserving( “click”,| notifica);|| // todos los handlers de un evento| $( “buy”).stopObserving( “click”);|| // todos los eventos/handlers| $( “buy”).stopObserving();
aitor.name
Eventos > Propagación
● Event.stop(): 2x1, previene la propagación del evento y la realización de la acción por defecto
● Evitamos los poco estéticos “#” al final de las URLs (por los <a href=”#” ...>)
| $( “comprar”).observe( “click”,| function( evt) {| Event.stop( evt);| }| });
aitor.name
Javascript > Ruby.clone()
● Prototype nació con RoR, es natural que quiera hacer Javascript lo más similar a Ruby
● Principales características● Estilo funcional con los iteradores● Programación OO● Mejoras al sistema de funciones
aitor.name
Javascript > Iteradores
● Característica fundamental de Prototype● Hace el lenguaje más “funcional” (tipo Lisp o
Haskell)● Implementado por un “mixin” llamado
Enumerable● “mixin”: conjunto de métodos (funciones) que
no se usan solos, si no que se incorporan a otros objetos
● Usos principales: Array, Hash
aitor.name
Javascript > Iteradores
● Iterando con each()
| [ “one”, “two”, “three”].each( | function( msg) {| alert( msg);| }| );| | [“one”, “two”, “three”].each(alert);
aitor.name
Javascript > Iteradores
● Búsquedas con find() y findAll()
| [ 1, 7, -2, -4, 5].find(| function(n) { return n < 0;}| );| // � -2|| [ 1, 7, -2, -4, 5].findAll( | function(n) { return n < 0; }| );| // � [ -2, -4]
aitor.name
Javascript > Iteradores
● Otras funcionalidades
| $$( “#main .warning”).invoke( hide);|| [“Erase”,"una",“vez”,“un”,“circo”].| map( function(s) {| return s.charAt( 0).toUpperCase();| });|| //� ['E', 'U', 'V', 'U', 'C']
aitor.name
Javascript > Iteradores
● Hay muchos iteradores que simplifican el código (una vez aprendidos)
| // all, any, collect, detect, each,| // eachSlice, entries, every, | // filter, find, findAll, grep,| // inGroupsOf, include, inject,| // inspect, invoke, map, max, min,| // parition, pluck, reject, select,| // size, some, sortBy, zip
aitor.name
Javascript > OOP
● Javascript es un lenguaje OO basado en prototipos
● Esto es muy útil, pero el resto del mundo usa clases
● Prototype ofrece extensiones para implementar algo que se parece a classes OOP
● Como todo en Prototype, con cierto sabor a Ruby
aitor.name
Javascript > OOP > Crear clases| var Person = Class.create( {| initialize: function(name) {| this.name = name;| },| say: function(message) {| return this.name + ': ' +| message;| }| });|| var paris = new Person( “Paris H”);| paris.say( “uhhh”);|| // � “Paris H: uhhh”
aitor.name
Javascript > OOP > Extender clases| var Pirate = Class.create(Person, {| say: function( $super, message) {| return $super( message) +| “, yarr!”;| }| });|| var john = new Pirate(“Long John”);| john.say( “ahoy matey”);|| // � "Long John: ahoy matey, yarr!"
aitor.name
Javascript > OOP > Mixins| // base class| var IceCream = Class.create( {...});|| // mixins| var Cookie = {...},| Cream = {...};|| var häagenDaz = Class.create( | IceCream,| Cookie, Cream, {| }| );
aitor.name
Javascript > function
● En Javascript las funciones son “first-class”: son objetos en sí mismas
● Como tal tienen propiedades+métodos y se pueden manejar como otros objetos
aitor.name
Javascript > function > bind
● Fija la función a un contexto de forma que al ser llamada nos aseguramos de que “this” hace referencia a ese contexto
● Puede parecer un poco complejo al principio pero es muy útil
aitor.name
Javascript > function > bind
| function message() {| return "Head and " + this;| }|| var human = message.bind( "body");| human(); // � "Head and body"| | var mrPotato = message.bind("legs");| mrPotato(); // � "Head and legs"
aitor.name
Javascript > function > bind
● Especialmente útil en gestión de eventos
| var AlertOnClick = Class.create( {| initialize: function( msg) {| this.msg = msg;| },| handleClick: function( event) {| alert( this.msg);| }| });
aitor.name
Javascript > function > bind
| var myalert = new AlertOnClick(| "Clicked!");|| $( “foo”).observe( “click”,| myalert.handleClick| ); // � FAIL ( “this” es invalido)| | $( “bar”).observe( “click”,| myalert.handleClick.| bind( myalert)| ); // � WIN ( “this” == objeto)
aitor.name
AJAX
● La clase Ajax.Request permite realizar peticiones AJAX en una forma OO
| new Ajax.Request( "/your/url", {| onSuccess: function( response) {| // handle the response content...| },| onFailure: function( response) {| // handle error| }| });
aitor.name
AJAX
● Hay diferentes tipos de callbacks
● Se puede configurar la petición
| // onCreate, onLoading, onLoaded,| // onException, onComplete, on{XYZ}| // ...
| // asynchronous, contentType,| // method, parameters, postBody,| // requestHeaders, sanitizeJSON ...
aitor.name
UI + FX
● Prototype se centra en las funcionalidades “core” y no ofrece soporte para temas de interfaz (widgets/efectos)
● Esta parte está implementada por la librería Script.aculo.us, la cual hace uso de Prototype
● Script.aculo.us ofrece animaciones, soporte drag & drop y algo de widgets
● La nueva versión 2.0 se llama Scripty2 (reescrita desde cero: muchas mejoras)
aitor.name
Otras funcionalidades
● Utilidades para trabajar con formularios● Muchas extensiones a los tipos de datos
nativos de Javascript (Array, Hash, Number, Object, String, RegExp...)
● Creación de nuevos “tipos de datos” como ObjectRange
aitor.name
Futuro
● Extender el DOM parecía una buena idea● La experiencia a demostrado que fue un error● Hay muchos problemas con la extensión del
DOM● Bajo rendimiento en navegadores con un DOM no
fácilmente extendible (IE6)● El DOM de IE es un desastre● Bugs en las implementaciones del DOM● Colisiones con los nombres de métodos/atributos
(→ getElementByClassName)
aitor.name
Futuro
● Prototype 2.0 usará la misma técnica que jQuery: wrappers de objetos
● Incompatibilidad total con Prototype 1
| // prototype| [ 1, 2, 3].each( function( e) {| console.log( e);| });| // jquery| $.each( [ 1, 2, 3], function(i,e) {| console.log( e);| });