06.09.2017 Views

coffeescript

Create successful ePaper yourself

Turn your PDF publications into a flip-book with our unique Google optimized e-Paper software.

CoffeeScript<br />

Un pequeño gran libro<br />

Javi Jimenez<br />

Este libro está a la venta en http://leanpub.com/<strong>coffeescript</strong><br />

Esta versión se publicó en 2013-12-17<br />

This is a Leanpub book. Leanpub empowers authors and<br />

publishers with the Lean Publishing process. Lean Publishing is<br />

the act of publishing an in-progress ebook using lightweight tools<br />

and many iterations to get reader feedback, pivot until you have<br />

the right book and build traction once you do.<br />

This work is licensed under a Creative Commons<br />

Attribution-NonCommercial-NoDerivs 3.0 Unported License


¡Twitea sobre el libro!<br />

Por favor ayuda a Javi Jimenez hablando sobre el libro en Twitter!<br />

El hashtag sugerido para este libro es #libro<strong>coffeescript</strong>.<br />

Descubre lo que otra gente está diciendo sobre el libro haciendo<br />

click en este enlace para buscar el hashtag en Twitter:<br />

https://twitter.com/search?q=#libro<strong>coffeescript</strong>


Dedicado a todas las personas que me sufren día a día.


Índice general<br />

Agradecimientos . . . . . . . . . . . . . . . . . . . . . . . . 1<br />

Prefacio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2<br />

JavaScript, El lenguaje padre . . . . . . . . . . . . . . . . 3<br />

CoffeeScript, El hijo bastardo . . . . . . . . . . . . . . . 4<br />

Un libro por el mundo . . . . . . . . . . . . . . . . . . . 5<br />

1. Comenzando . . . . . . . . . . . . . . . . . . . . . . . . 7<br />

1.1 Entorno necesario . . . . . . . . . . . . . . . . . . . . 7<br />

1.2 Instalando NodeJS . . . . . . . . . . . . . . . . . . . . 8<br />

1.3 Instalando CoffeeScript . . . . . . . . . . . . . . . . . 11<br />

2. Sintaxis . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13<br />

2.1 Valores, variables y comentarios . . . . . . . . . . . . 13<br />

2.2 Interpolación de cadenas . . . . . . . . . . . . . . . . 15<br />

2.3 Control de flujo . . . . . . . . . . . . . . . . . . . . . 16<br />

2.4 Loops . . . . . . . . . . . . . . . . . . . . . . . . . . 18<br />

2.5 Alias y Operadores . . . . . . . . . . . . . . . . . . . 22<br />

3. Funciones, Ámbito y Contexto . . . . . . . . . . . . . . 26<br />

3.1 Funciones . . . . . . . . . . . . . . . . . . . . . . . . 26<br />

3.2 Funciones y Argumentos . . . . . . . . . . . . . . . . 27<br />

3.3 Llamando a funciones . . . . . . . . . . . . . . . . . . 31<br />

3.4 Ámbito . . . . . . . . . . . . . . . . . . . . . . . . . . 33<br />

3.5 Contexto . . . . . . . . . . . . . . . . . . . . . . . . . 36<br />

3.6 Cambio de contexto en funciones . . . . . . . . . . . 39


ÍNDICE GENERAL<br />

4. Objetos y Arrays . . . . . . . . . . . . . . . . . . . . . . 41<br />

4.1 Recordando JavaScript y sus Objetos . . . . . . . . . . 41<br />

4.2 Objetos . . . . . . . . . . . . . . . . . . . . . . . . . . 42<br />

4.3 Arrays . . . . . . . . . . . . . . . . . . . . . . . . . . 45<br />

4.4 Comprensiones . . . . . . . . . . . . . . . . . . . . . 50<br />

5. Clases . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52<br />

5.1 Prototipos . . . . . . . . . . . . . . . . . . . . . . . . 52<br />

5.2 Clases . . . . . . . . . . . . . . . . . . . . . . . . . . 55<br />

5.3 Herencia . . . . . . . . . . . . . . . . . . . . . . . . . 58<br />

5.4 Polimorfismo . . . . . . . . . . . . . . . . . . . . . . 61<br />

6. Modularización . . . . . . . . . . . . . . . . . . . . . . . 63<br />

6.1 Namespacing . . . . . . . . . . . . . . . . . . . . . . 63<br />

6.2 Mixins . . . . . . . . . . . . . . . . . . . . . . . . . . 64<br />

6.3 Extendiendo clases . . . . . . . . . . . . . . . . . . . 65<br />

7. Bibliografía . . . . . . . . . . . . . . . . . . . . . . . . . 68


Agradecimientos<br />

Escribir un libro en estos tiempos tan sumamente acelerados supone<br />

un gran esfuerzo. Principalmente necesitas tiempo y normalmente<br />

la gente no está dispuesta a dártelo; es por eso que doy las gracias<br />

a todas esas personas que me han permitido gastar mi tiempo en lo<br />

que hoy considero importante.<br />

Dar las gracias a mi familia por siempre haberme permitido tener<br />

la libertad que he necesitado para poder equivocarme, conocerme<br />

y ser la persona que hoy soy.<br />

Dar las gracias al equipo de Tapquo¹: Ina, Cata, Oihane, Janire y<br />

Joseba por continuar con el día a día de nuestra loca empresa y<br />

seguir con el propósito que nos hemos marcado juntos.<br />

Dar las gracias a accionistas, consejeros y amigos de Tapquo por<br />

confiar en mi y darme la libertad para escaparme del país y<br />

centrarme en este texto que ahora lees.<br />

Dar las gracias también a Jeremy Ashkenas por crear el lenguaje<br />

CoffeeScript y contribuir altruistamente a la evolución del mundo<br />

web, sin olvidar a los numerosos contribuyentes al proyecto, y a<br />

otros proyectos OpenSource, que por suerte son demasiados para<br />

nombrarlos uno a uno aquí.<br />

Por último quiero darte las gracias a ti, gracias por descargarte<br />

este libro y darme una oportunidad de contarte lo que ha supuesto<br />

CoffeeScript en mi vida. Lo mucho que nos ha ayudado dentro de<br />

Tapquo creando un mejor código, más mantenible y más comprensible.<br />

Ahora solo te pido una última cosa, comparte este libro cómo lo<br />

he hecho yo contigo, regálalo y ayúdame a transmitir este contenido<br />

por el mundo.<br />

¹http://tapquo.com


Prefacio<br />

Tal vez no sabes muy bien porqué estás leyendo este pequeño libro<br />

sobre CoffeeScript, antes de nada piensa en este libro como un<br />

regalo que te ofrezco, no espero nada a cambio, únicamente que<br />

disfrutes con su lectura tanto como yo he disfrutado escribiéndolo.<br />

Te preguntarás por qué he decidido escribir un libro en castellano<br />

sobre CoffeeScript, y no sobre JavaScript como muchos esperaban<br />

que hiciera. Razones tengo muchas pero la principal es que tal<br />

vez sea el lenguaje con el que más me he divertido mientras lo<br />

descubría y el que más me ha ayudado a mejorar mis capacidades<br />

como desarrollador web. No te puedes hacer una idea lo que ha<br />

supuesto CoffeeScript para mi y por lo tanto para la empresa que<br />

fundé, Tapquo². Quiero contarte mis inicios con este maravilloso<br />

lenguaje y también su propia génesis, comencemos.<br />

La primera vez que escuché de CoffeeScript fue gracias a mi amigo<br />

Guillermo Pascual³ cuando en Septiembre del 2011 estábamos en la<br />

primera oficina de Tapquo desarrollando, y refactorizando, lo que<br />

iba a ser la primera versión de LungoJS⁴. Al principio no le presté<br />

mucha atención a CoffeeScript, pretendía ser mejor programador<br />

en JavaScript y Lungo iba a ser mi primer gran exponente, tenia<br />

puesto el Focus y no debía dispersarme con eso que nos gusta tanto<br />

a los Developers; aprender un nuevo lenguaje.<br />

Fue en Junio del 2012, una vez que Lungo ya era estable y yo ya<br />

dominaba JavaScript como pretendía, cuando dediqué mi tiempo<br />

a CoffeeScript. Comencé leyendo varios libros, tampoco había<br />

muchos más, los cuales me han ayudado a escribir el libro que<br />

²http://tapquo<br />

³http://twitter.com/pasku1<br />

⁴http://lungo.tapquo.com


Prefacio 3<br />

estas ahora leyendo. Enseguida obtuve el Flow con el lenguaje, ya<br />

que como proscrito Rubista y actual adorador de Python⁵, tanto la<br />

sintaxis como las estructuras me resultaban muy familiares. Tanto<br />

es así que en dos semanas de estudio me decidí a crear un micro<br />

Framework MVC, Monocle⁶, el cual intentaba aprovechar lo mejor<br />

de CoffeeScript y que actualmente además de usarlo activamente<br />

en nuestros locos días de oficina lo usan miles de desarrolladores<br />

por todo el mundo.<br />

Solo me queda pedirte una cosa, ¡diviértete!, diviértete aprendiendo<br />

este lenguaje lleno de buenas intenciones y de alguna que otra<br />

sorpresa.<br />

JavaScript, El lenguaje padre<br />

Si recibiese un BitCoin por cada vez que oigo que JavaScript no es<br />

un gran lenguaje ahora mismo tendría un buen puñado de monedas<br />

virtuales en mi bolsillo. JavaScript nunca ha sido, ni será, el lenguaje<br />

de programación más utilizado y más famoso del mundo, para eso<br />

tenemos a C o Java. Voy a ponerte en contexto, fue desarrollado<br />

en apenas 10 días por el genio Brendan Eich⁷ con la única premisa:<br />

tener una sintaxis muy parecida al lenguaje C, y esa es la única similitud<br />

con el lenguaje C. Como rezan algunos “cualquier parecido con<br />

la realidad es pura casualidad” y es por eso que desde sus inicios el<br />

nombre ha generado muchas equivocaciones, confundiendolo con<br />

una versión ligera de Java para la web.<br />

Lo que es seguro es que desde sus inicios en 1995 JavaScript ha<br />

seguido en constante evolución:<br />

• 1995 Primera versión<br />

• 1998 ECMA-262 1st + 2nd edition<br />

⁵https://en.wikipedia.org/wiki/Python_(programming_language)<br />

⁶http://monocle.tapquo.com<br />

⁷https://en.wikipedia.org/wiki/Brendan_Eich


Prefacio 4<br />

• 2000 ECMA-262 3rd edition<br />

• …<br />

• 2005 AJAX, Array Extras, string generics… (v1.5)<br />

• 2006 Iterators, Pythonic generators… (v1.6)<br />

• 2008 Generator expressions, expression closures, JSON support…(v1.7-<br />

v1.8)<br />

• …<br />

• 2010 EcmaScript5 (v1.8.2)<br />

• …<br />

• 2014 EcmaScript6<br />

El gran problema que ha tenido JavaScript es que la forma de<br />

desarrollar nunca ha sido comprendida ni para los desarrolladores<br />

de la vieja escuela (C, Java…), que se quejaban de la falta de clases y<br />

demás singularidades de la OOP, ni para los que solo han trabajado<br />

con lenguajes modernos (Python, Ruby, Haskell…), que maldecían<br />

la verbosidad barroca, con las conocidas llaves, paréntesis y puntos<br />

y comas. Por lo tanto siempre ha sido criticado y en mi opinión<br />

siempre lo será. Como todos los lenguajes, JavaScript tiene defectos,<br />

pero poco a poco y con cada nueva revisión se van puliendo y<br />

mejorando.<br />

En este libro vamos a acercarnos a JavaScript por medio de CoffeeScript,<br />

pretendo que seas mejor desarrollador JavaScript de lo<br />

que has sido hasta ahora. Mi propósito es que respetes al Lenguaje<br />

Padre y que puedas enfrentarte a proyectos con las suficientes lineas<br />

de código que asuste al mejor de los Gurus de jQuery⁸ (sarcasmo).<br />

CoffeeScript, El hijo bastardo<br />

CoffeeScript es un lenguaje de programación el cual es capaz de<br />

compilar su resultado a JavaScript, es unicamente eso. Está totalmente<br />

inspirado en la sintaxis de lenguajes como Ruby, Python y<br />

⁸http://jquery.com


Prefacio 5<br />

Haskell para capacitar a JavaScript de una expresividad y brevedad<br />

que por si solo no tiene. Tus programas en JavaScript se escribirán<br />

con menos lineas de CoffeeScript, mas o menos una proporción<br />

1/3, sin tener ninguna perdida de rendimiento (incluso a veces la<br />

mejora).<br />

Su autor es Jeremy Ashkenas⁹ y comenzó con el proyecto el 13<br />

de Diciembre del 2009 con un misterioso e intrigante comentario<br />

en su primer commit en GitHub "initial commit of the<br />

mystery language". Comenzó creando el compilador en Ruby<br />

pero en apenas 3 meses cambio de idea e hizo que el compilador<br />

estuviese escrito con su propio lenguaje, CoffeeScript. El proyecto<br />

pronto fue seguido por multitud de desarrolladores en GitHub¹⁰,<br />

donde tanto Jeremy como el resto de contribuyentes añadían nuevas<br />

características cada mes.<br />

Después de publicarse la versión 1.0 en navidades del 2010, CoffeeScript<br />

se convirtió en uno de los proyectos más seguidos en GitHub.<br />

El lenguaje volvió a tener un empujón en la escena web, cuando en<br />

Abril del 2011 David Heinemeier Hansson¹¹ confirmó los rumores<br />

que decían que CoffeeScript iba a estar incluido en la versión 3.1 de<br />

Ruby on Rails.<br />

Y yo me pregunto ¿como puede ser que un lenguaje tan pequeño<br />

haya captado tanto interés? Tres razones me vienen a la mente:<br />

divertido, seguro y fácil de leer.<br />

Un libro por el mundo<br />

Este libro fue escrito durante mi viaje por Tailandia, en los meses<br />

de Noviembre y Diciembre del año 2013. Decidí irme a 12.000km<br />

de mi lugar de residencia para centrarme en el libro y poder dar<br />

lo mejor de mi en él. Uno de mis propósitos en la vida es ofrecer<br />

⁹https://en.wikipedia.org/wiki/Jeremy_Ashkenas<br />

¹⁰https://github.com/jashkenas/coffee-script<br />

¹¹https://en.wikipedia.org/wiki/David_Heinemeier_Hansson


Prefacio 6<br />

mi conocimiento a todo aquel que quiera adquirirlo y esta es una<br />

buena manera de hacerlo. Ahora tú tienes que ayudarme a regalar<br />

este libro a tus amigos, no te ha costado nada y no te costará nada<br />

hacerlo.<br />

Mi próximo libro tratará sobre EcmaScript 6¹² y lo escribiré en<br />

Nueva Zelanda, por lo que si después de leer este libro te ha gustado<br />

tanto como para hacer una donación¹³, financiando así parte del<br />

próximo libro, te estaré eternamente agradecido.<br />

¹²https://en.wikipedia.org/wiki/ECMAScript<br />

¹³leanpub.com/<strong>coffeescript</strong>


1. Comenzando<br />

Si has leído el prefacio, se puede decir que ya conoces el origen de<br />

CoffeeScript, que es lo que trae y porque es una de las mejores cosas<br />

que le han pasado a los programadores web en estos últimos años.<br />

Ahora mismo no eres capaz de escribir una sola linea, así que te voy<br />

a ayudar a preparar tu entorno de trabajo con CoffeeScript.<br />

1.1 Entorno necesario<br />

En el prefacio has aprendido que el compilador de CoffeeScript esta<br />

escrito en CoffeeScript. Curiosidades aparte, tienes que ser capaz de<br />

resolver la siguiente cuestión:<br />

¿Cómo puedo ejecutar el compilador en mi sistema si todaviá<br />

no tengo el compilador de CoffeeScript?<br />

¿No? Te voy a ayudar a encontrar la solución preguntándote de<br />

nuevo; si hubiera una manera de ejecutar JavaScript en tu maquina<br />

sin utilizar un navegador web y mostrar el código al sistema<br />

operativo… ¿Sigues sin caer? ¿De verdad?<br />

Es muy sencillo, no hace falta más que utilizar NodeJS¹⁴ y he<br />

aquí donde viene un punto de aclaración; mucha gente entiende<br />

“Node” como un servidor web en JavaScript pero, por suerte, es<br />

mucho más que eso y cada vez está más presente en soluciones<br />

que nada tienen que ver con el mundo de los servidores web.<br />

Fundamentalmente NodeJS es un puerta entre tu código JavaScript<br />

y el sistema operativo, trayendo consigo una potente herramienta<br />

llamada NPM¹⁵, Node Package Manager, que lo hace extensible<br />

¹⁴http://nodejs.org<br />

¹⁵http://npmjs.org


1. Comenzando 8<br />

infinitamente. Si vienes del mundo de Ruby piensa en NPM como<br />

una analogiá a las Gems.<br />

El resto de este área se centrará en como instalar NodeJS, que por<br />

supuesto necesitaremos para usar CoffeeScript y su compilador.<br />

Pero si no puedes esperar más y quieres intentar codificar tus<br />

primeras lineas en CoffeScript echa un pequenõ vistazo al Try<br />

CoffeeScript¹⁶ de la página oficial.<br />

1.2 Instalando NodeJS<br />

Existen dos formas de instalar nodeJS, mediante el código fuente<br />

del proyecto (y su posterior compilación) o bien descargando una<br />

instalación con el proyecto ya compilado. Independientemente del<br />

sistema operativo que uses no tendrás grandes problemas, pero si<br />

que puedo decir que por mi experiencia los que más problemas<br />

suelen tener con la instalación han sido los usuarios de Linux.<br />

Veamos como instalarlo en cada uno de los sistemas operativos:<br />

Mac<br />

Si eres usuario como yo del maravilloso Brew¹⁷ (homebrew package<br />

manager), unicamente tendrás que ejecutar el comando:<br />

brew install node<br />

En caso contrario sigue los siguientes pasos:<br />

• Instala Xcode<br />

• Instala GIT<br />

• Ejecuta los siguientes comandos:<br />

¹⁶http://<strong>coffeescript</strong>.org<br />

¹⁷http://brew.sh/


1. Comenzando 9<br />

darwin_setup.sh<br />

git clone git://github.com/ry/node.git<br />

cd node<br />

./configure<br />

make<br />

sudo make install<br />

Linux (Ubuntu)<br />

Antes de compilar NodeJS necesitamos añadir las siguientes dependencias<br />

a tu sistema:<br />

sudo apt-get install g++ curl libssl-dev apache2-utils<br />

sudo apt-get install git-core<br />

Ahora ejecuta los mismos comandos que en la instalación en Mac:<br />

ubuntu_setup.sh<br />

git clone git://github.com/ry/node.git<br />

cd node<br />

./configure<br />

make<br />

sudo make install<br />

Windows<br />

Justo para este sistema voy a recomendar encarecidamente el uso de<br />

los downloads oficiales desde la sección de descargas¹⁸ de NodeJS.<br />

El cual lo único que te pedirá es reiniciar el sistema para que NodeJS<br />

esté disponible.<br />

¹⁸http://nodejs.org/download/


1. Comenzando 10<br />

Tu primer servidor NodeJS<br />

Vamos a crear un pequeño programa para comprobar que todo<br />

está funcionando correctamente, antes de ello ejecuta el siguiente<br />

comando para comprobar la versión de la que dispones:<br />

node -v<br />

Ahora viendo que tienes una versión reciente (por tu bien) vas a<br />

crear un pequeño servidor con un único fichero, a este le llamaras<br />

hello_node.js:<br />

hello_node.js<br />

var http = require('http');<br />

http.createServer(function (request, response) {<br />

response.writeHead(200, {'Content-Type': 'text/plain'\<br />

});<br />

response.end('Hello Node.js\n');<br />

}).listen(1337, "127.0.0.1");<br />

console.log('Server running at http://127.0.0.1:1337/');<br />

Ahora toca ver si el servidor arranca correctamente ejecutando el<br />

NCL (Node Command Line):<br />

node hello_node.js<br />

Si todo va bien deberías ver por tu pantalla el mensaje Server<br />

running at http://127.0.0.1:1337/, si es asi vete a tu browser<br />

a esa misma dirección y aparecerá por pantalla un bonito mensaje.<br />

Desde este momento puedo decirte que tienes NodeJS listo y funcionando<br />

para empezar con CoffeeScript.


1. Comenzando 11<br />

1.3 Instalando CoffeeScript<br />

Ahora que ya tenemos NodeJS la instalación de nuestro nuevo<br />

lenguaje favorito va a ser sencilla ya que utilizaremos NPM con<br />

el comando:<br />

sudo npm install -g coffee-script<br />

Como ves he puesto sudo (solo para mac/linux) y los parámetros<br />

install (evidente) y -g para que lo instale globalmente seguido de<br />

coffee-script que en este caso es el paquete que queremos instalar.<br />

Tras la instalación debes comprobar que versión de CoffeeScript<br />

tienes en el sistema:<br />

coffee -v<br />

Si aparece una nueva versión de CoffeeScript la actualización<br />

es relativamente sencilla ya que únicamente tienes que volver a<br />

utilizar NPM cambiando un único parámetro ¿ya sabes cual es?:<br />

sudo npm update -g coffee-script<br />

Ahora que ya tienes CoffeeScript vamos a ver si funciona todo<br />

correctamente creando una simple función desde el terminal con<br />

la consola coffee:<br />

coffee


1. Comenzando 12<br />

coffee> sum = (a, b) -> a + b<br />

coffee> sum 1, 2<br />

3<br />

coffee> sum 3, 4<br />

7<br />

Se que no sabes lo que has escrito, no es la idea de este capítulo,<br />

aunque por la sintaxis y los operadores puedes llegar a sacar una<br />

conclusión. En el siguiente capitulo vas a conocer más de la sintaxis<br />

de este lenguaje y descubrirás lo bien hecho que está y lo divertido<br />

que es programar con el.


2. Sintaxis<br />

Antes de comenzar con este capítulo asumo que tienes una base en<br />

JavaScript, y eso no quiere decir que sabes usar jQuery o cualquier<br />

otra librería. Sino es así te recomiendo que estudies el Lenguaje<br />

Padre antes de comenzar con el hijo bastardo. De una manera u otra<br />

mi responsabilidad como desarrollador JavaScript es recomendarte<br />

que al menos conozcas, leas y comprendas estos dos libros:<br />

• JavaScript, the good parts¹⁹ (Douglas Crockford)<br />

• Eloquent JavaScript²⁰ (Marijn Haverbeke)<br />

En ellos descubrirás algunas particularidades del lenguaje JavaScript<br />

y siempre te vendrá bien tenerlos a mano para poder repasar<br />

algún que otro concepto. En este capítulo vamos a aprender la<br />

sintaxis básica de CoffeeScript comprobando que comparte más<br />

similitudes con Ruby o Python que con JavaScript.<br />

2.1 Valores, variables y comentarios<br />

La creación y asignación de variables no difiere mucho de otro lenguaje<br />

de programación, tal vez la mayor diferencia con JavaScript<br />

es que no hace falta comenzar con var ni finalizar la declaración<br />

con el prehistórico caracter ;. Veamos un ejemplo sencillo:<br />

¹⁹http://www.amazon.com/JavaScript-Good-Parts-Douglas-Crockford/dp/0596517742<br />

²⁰http://eloquentjavascript.net/


2. Sintaxis 14<br />

heroe = "Superman"<br />

year = 1984<br />

Sencillo ¿no?, en el siguiente capítulo conocerás como CoffeeScript<br />

gestiona automáticamente el ámbito de nuestras variables, escapando<br />

del temido e ineficiente GlobalScope.<br />

En el caso de que necesites introducir cadenas de texto de mayor<br />

tamaño podríamos hacerlo de la siguiente manera:<br />

crockford[1] = "JavaScript doesn't suck! You're just do\<br />

ing it wrong."<br />

crockford[2] = "JavaScript doesn't suck!<br />

You're just doing it wrong."<br />

Aunque parezca increíble los 2 elementos del array crockford<br />

tienen el mismo contenido, y a pesar de que en la segunda parece<br />

que hemos hecho un salto de linea, CoffeeScript y su parseador<br />

darán en ambos casos como resultado:<br />

> 'JavaScript doesn't suck! You're just doing it wrong.'<br />

En el caso de que quieras generar un salto de linea te recomiendo<br />

que utilices el delimitador de string """ en vez de utilizar las<br />

prehistóricas concatenaciones de \n y \r:<br />

crockford[3] = """<br />

JavaScript doesn't suck!<br />

You're just doing it wrong."""<br />

El resultado de crockford[3] será:


2. Sintaxis 15<br />

> 'JavaScript doesn't suck!<br />

You're just doing it wrong.'<br />

Los comentarios dentro de nuestro código siguen el mismo patrón,<br />

utilizando el carácter # como delimitador:<br />

# Tu primer comentario<br />

Los comentarios multilinea también están soportados, y como te<br />

puedes imaginar vas a tener que triplicar el caracter # para que sean<br />

efectivos:<br />

###<br />

Un comentario multilinea,<br />

por ejemplo definir la licencia<br />

o autor del código fuente.<br />

###<br />

2.2 Interpolación de cadenas<br />

CoffeeScript nos da la interpolación de string de una manera<br />

similar a como lo hace Ruby. Dentro de una cadena delimitada por<br />

el caracter " podremos introducir la expresión #{}, la cual puede<br />

contener cualquier tipo de expresión que será interpolada a string:<br />

hero = "Batman..."<br />

chat = """<br />

friend : What... is your favorite hero?<br />

soyjavi: #{hero}<br />

friend : Seriously?"""<br />

Vamos a ver ahora un ejemplo algo más completo con operaciones<br />

numéricas donde descubrirás algo más de mi:


2. Sintaxis 16<br />

born = new Date(1980, 4, 10)<br />

now<br />

= new Date().getFullYear()<br />

answer = "@soyjavi was born in #{born.getFullYear()},<br />

."<br />

now has #{now - born.getFullYear()} years old\<br />

En mi opinión la interpolación es una solución mucho más elegante<br />

que la concatenación a base de ir anidando strings, variables y el<br />

caracter +.<br />

2.3 Control de flujo<br />

En este apartado vas a ver las estructuras para el control del<br />

flujo de tu aplicación, recordando que CoffeeScript esta lleno de<br />

convenciones que facilitan la escritura de buen código. Por ejemplo,<br />

no es necesario utilizar paréntesis en las expresiones if, else, for,<br />

… ni delimitar el ámbito del flujo con las aburridas Curly Braces {}.<br />

Veamos un ejemplo:<br />

if year == 1980<br />

born = true<br />

else<br />

born = false<br />

En este caso vemos que el ámbito del if lo marca el nivel de<br />

indentación donde solo hay una linea born = true, aunque<br />

podrías introducir todas las que necesites, además vemos que no<br />

es necesario introducir () y {}. Se recomienda que cada nivel de<br />

indentación sea de 2 espacios, aunque hay desarrolladores que<br />

utilizan 4 espacios no es muy recomendable ya que con cada nivel<br />

perdemos espacio para escribir nuestro código. De todas formas,<br />

podemos hacerlo de una forma más elegante, expresiva y en una<br />

sola linea de la siguiente manera:


2. Sintaxis 17<br />

if year is 1980 then born = true else born = false<br />

Como ves en este caso he introducido el alias operador is que<br />

es traducido a JavaScript como ===. En ambos casos el código<br />

resultante en JavaScript será el mismo, pudiendo comprobar que<br />

esta lleno de todos esos caracteres y convenciones de las que<br />

queremos escapar:<br />

var born;<br />

if (year === 1980) {<br />

born = true;<br />

} else {<br />

born = false;<br />

}<br />

Otra manera de hacer la misma operación seria utilizando un<br />

operador ternario:<br />

born = (if year is 1980 then true else false)<br />

Traduciendose a JavaScript de una forma bastante similar:<br />

born = (year === 1980 ? true : false);<br />

Ahora sigamos con alguna expresión más, por ejemplo en el caso<br />

de que solo necesites hacer una comparación if podríamos hacerlo<br />

al estilo Ruby:<br />

born = true if year is 1980<br />

Si quisiésemos hacer la negación de la sentencia anterior, esto<br />

es; establecer la variable born a false, podríamos utilizar el alias<br />

operador isnt que se traduce en JavaScript a !==. Veamos como:


2. Sintaxis 18<br />

born = false if year isnt 1980<br />

o también utilizando la expresión unless:<br />

born = false unless year is 1980<br />

En ambos casos puedes ver que el JavaScript resultante es el mismo:<br />

var born;<br />

if (year !== 1980) {<br />

born = false;<br />

}<br />

Ya hemos visto los alias is, unless y isnt más adelante podrás<br />

conocer más alias disponibles en CoffeeScript los cuales aportarán<br />

una mayor expresividad a tu código.<br />

2.4 Loops<br />

Una de las estructuras que más solemos utilizar como desarrolladores<br />

son las iteraciones o bucles, esto se expone claramente en los<br />

proyectos JavaScript donde al no existir muchos métodos dedicados<br />

para el tratamiento de arrays debemos leer el contenido de los<br />

mismos de forma iterada.<br />

En CoffeeScript vas a empezar por lo básico, pero en capítulos<br />

posteriores podrás ver que disponemos de hacks dedicados a los<br />

arrays los cuales te solventarán la vida. Vamos a ver como podrías<br />

crear un simple bucle contador con la expresión while:


2. Sintaxis 19<br />

heroes = 0<br />

while heroes


2. Sintaxis 20<br />

heroes = ["Batman", "Spiderman", "Superman"]<br />

for hero in heroes by 2<br />

console.log hero<br />

Con el incremental by 2, el resultado será:<br />

> "Batman", "Superman"<br />

Al igual que con las estructuras if, while, until podemos resolver<br />

el anterior ejemplo en una única y expresiva linea:<br />

console.log hero for hero in ["Batman", "Spiderman", "S\<br />

uperman"] by 2<br />

Ahora voy a complicarlo un poco más, filtrando el array por un<br />

determinado condicionante; en este caso nos vamos a quedar con<br />

los heroes que tengan como inicial la letra S:<br />

heroes = ["Batman", "Spiderman", "Superman"]<br />

console.log hero for hero in heroes when hero[0] is "S"<br />

Quiero que leas el código resultante en JavaScript, para comprobar<br />

que las estructuras que genera CoffeeScript son totalmente correctas,<br />

respetando declaración y ámbito de variables:


2. Sintaxis 21<br />

var hero, heroes, _i, _len;<br />

heroes = ["Batman", "Spiderman", "Superman"];<br />

for (_i = 0, _len = heroes.length; _i < _len; _i++) {<br />

hero = heroes[_i];<br />

if (hero[0] === "S") {<br />

console.log(hero);<br />

}<br />

}<br />

En el caso de que necesites de estructuras iterativas abiertas, lo<br />

mejor es que utilices la expresión loop. La cual nos da un mayor<br />

control sobre el flujo de control de nuestro bucle ya que siempre<br />

está iterando hasta que se cumpla algún condicionante dentro de el<br />

y demos por finalizo el proceso con la expresión break. Veamos un<br />

ejemplo:<br />

heroes = 2<br />

loop<br />

break if heroes is 8<br />

heroes++<br />

console.log heroes<br />

Como puedes leer el bucle terminará cuando la variable heroes sea<br />

igual a 8, ya que la expresión break ejecuta la linea inmediata a<br />

la estructura loop. Vamos a echar un vistazo a como quedaría el<br />

código en JavaScript:


2. Sintaxis 22<br />

var heroes = 2;<br />

while (true) {<br />

if (heroes === 8 {<br />

break;<br />

}<br />

heroes++;<br />

}<br />

console.log(heroes);<br />

2.5 Alias y Operadores<br />

Ya sabes que una de las premisas de CoffeeScript es intentar crear<br />

código expresivo, por ahora hemos visto algunos operadores como<br />

is, isnt, unless y desde esta sección conoceremos más facilitadores<br />

para nuestro código CoffeeScript.<br />

Como ya sabes is es traducido al comparador === y su contrario<br />

isnt es traducido a !==, en el caso de que quieras hacer una<br />

negación ! deberás utilizar el operador not. Veamos un ejemplo:<br />

facebook_account = false<br />

if not facebook_account<br />

console.log "Well done!!"<br />

Ahora quiero hacerte una pregunta ¿Como lees en lenguaje natural<br />

los operadores en JavaScript || y &&?, me imagino que la respuesta<br />

que te habrás dado a ti mismo ha sido or y and. Bien, pues<br />

CoffeeScript intenta crear lenguaje natural en tu código facilitando<br />

que cualquier persona pueda entender lo que pretendes hacer con<br />

el. Veamos un ejemplo:


2. Sintaxis 23<br />

facebook_account = false<br />

twitter_account = false<br />

if not facebook_account and not twitter_account<br />

console.log "You're a caveman."<br />

El operador or también puedes utilizarlo para inicializar variables<br />

con valores por defecto. Pongamos el caso de que queremos almacenar<br />

en la variable where el valor de location solo cuando este<br />

sea distinto de undefined, en caso contrario establecemos el valor<br />

string "Gotham"<br />

where = location or "Gotham"<br />

El operador existencial ? puede ayudarnos a que el ejercicio anterior<br />

sea más preciso, dado que si la variable location no esta declarada<br />

dará un error de compilación. Utilizando ? nos aseguramos que<br />

comprueba que location no sea ni undefined ni null:<br />

where = location ? "Gotham"<br />

Veamos como queda esta mínima sentencia en JavaScript:<br />

var where;<br />

where = typeof location !== "undefined" && location !==\<br />

null ? location : "Gotham";<br />

El operador existencial ? te puede servir para muchos más contextos,<br />

por ejemplo imagina que tienes una librería basada en<br />

módulos y quieres llamar a un método solo si existe un determinado<br />

namespace:


2. Sintaxis 24<br />

batman.vehicles?.batMobile()<br />

Aquí vemos algo de la magia de CoffeeScript, en el caso de que la<br />

propiedad vehicles de batman no exista, no ejecutará el método<br />

batMobile. Traduciendo la anterior sentencia a JavaScript quedaría<br />

de la siguiente manera:<br />

var _ref;<br />

if ((_ref = batman.vehicles) != null) {<br />

_ref.batMobile();<br />

}<br />

Imagina ahora que quieres ejecutar el método kamehame siempre<br />

y cuando sea una función ejecutable, simplemente cambiando la<br />

posición del operador ? lo tendrás resuelto:<br />

goku.movements?.kamehame?()<br />

Echa un vistazo a su traducción en JavaScript:<br />

var _ref;<br />

if ((_ref = goku.movements) != null) {<br />

if (typeof _ref.kamehame === "function") {<br />

_ref.kamehame();<br />

}<br />

}<br />

Uno de los alias que más me sorprendió cuando aprendí CoffeeScript<br />

fue @ el cual se utiliza para sustituir el típico this:<br />

@twitter = "@soyjavi"


2. Sintaxis 25<br />

Lo que estamos haciendo en este caso es establecer la variable del<br />

contexto actual twitter con el valor "@soyjavi". En el próximo<br />

artículo veremos como podemos conmutar de contextos de una manera<br />

sencilla, lo cual nos será de gran ayuda en muchas ocasiones.<br />

El último alias que vas a ver será :: que hace referencia a prototype,<br />

entendiendo que con tu base actual de JavaScript sabes perfectamente<br />

a que me refiero.<br />

Goku::life = 10<br />

Si no sabes muy bien de lo que te estoy hablando has incumplido el<br />

pacto conmigo, ¡debes estudiar JavaScript!. En el capítulo 5, clases,<br />

darémos un pequeño repaso al paradigma de los prototipos en<br />

JavaScript con CoffeeScript.


3. Funciones, Ámbito y<br />

Contexto<br />

CoffeeScript elimina todo adorno barroco en la declaración de<br />

funciones tal y como estás acostumbrado en la programación con<br />

JavaScript. Lo sustituye por un símbolo simple y conciso como es -><br />

y como verás más adelante deberás dominarlo si quieres convertirte<br />

en un verdadero CoffeeScripter.<br />

Las funciones pueden declararse en una sola linea o en varias<br />

lineas indentadas como por ejemplo se hace en otros lenguajes<br />

como son Ruby o Python. Otra de las cosas maravillosas que te<br />

vas a encontrar es que no hace falta definir el return de nuestra<br />

función ya que existe una convención donde la última expresión que<br />

definamos dentro de una función automáticamente se convertirá en<br />

el resultado de la misma. En otras palabras no es necesario utilizar<br />

la sentencia return a menos que necesites que el flujo de tu función<br />

necesite devolver algo antes.<br />

3.1 Funciones<br />

Como vale más un ejemplo que mil palabras, con la siguiente linea<br />

te descubro tu primera función en CoffeeScript:<br />

hello = -> “world”<br />

Como puedes ver he creado una función llamada hello la cual<br />

devuelve automáticamente la cadena de texto “world”, lo se, no es<br />

una función pretenciosa pero si la compilas veras que el resultado<br />

en JavaScript cambia bastante:


3. Funciones, Ámbito y Contexto 27<br />

var hello = function() {<br />

};<br />

return “world”;<br />

Como he comentado anteriormente a menos que sea estrictamente<br />

necesario no es necesario declarar funciones en múltiples lineas.<br />

Pero la función hello podría codificarse de la siguiente manera:<br />

hello = -><br />

# ... amazing CoffeeScript code!<br />

“world”<br />

La compilación en JavaScript seguirá siendo exactamente igual que<br />

en la primera función hello, por lo que en este punto tu decidirás<br />

cuando y porqué utilizar funciones en una sola linea, recordando<br />

siempre el respeto por el Clean Code²².<br />

3.2 Funciones y Argumentos<br />

Como hemos visto la declaración de funciones es sumamente<br />

sencilla, pero el ejemplo anterior es poco versátil ya que únicamente<br />

devuelve un valor constante. Veamos una función algo más dinámica:<br />

divide = (a, b) -> a / b<br />

En esta ocasión tenemos una función divide que recibe dos argumentos<br />

a y b los cuales se dividen entre si y se devuelve el resultado.<br />

Esto mismo compilado en JavaScript:<br />

²²http://www.amazon.com/Clean-Code-Handbook-Software-Craftsmanship/dp/<br />

0132350882


3. Funciones, Ámbito y Contexto 28<br />

var divide = function(a, b) {<br />

};<br />

return a / b;<br />

Una de las cosas que más cuesta en JavaScript es el control de<br />

valores en argumentos de una función, pero gracias a CoffeeScript el<br />

trabajo se simplifica considerablemente. Por ejemplo, imagina que<br />

en nuestra función divide queremos que el argumento b por defecto<br />

sea 1 si no introducimos ningún valor:<br />

divide = (a, b = 1) -> a / b<br />

Como ves sigue siendo muy sencillo y curiosamente sigue siendo<br />

una sola linea de código, pero si analizamos la compilación en<br />

JavaScript:<br />

var divide;<br />

divide = function(a, b) {<br />

if (b == null) {<br />

b = 1;<br />

}<br />

return a / b;<br />

};<br />

Si estudiamos el código vemos que controla si el argumento b es<br />

null, en caso de que lo sea automáticamente lo inicializa con el<br />

valor 1. Si no te acabas de convencer de porqué CoffeeScript es una<br />

de los mejores complementos para desarrollar Aplicaciones Webs,<br />

te recomiendo que cierres este libro y te dediques a otra cosa.<br />

Si estas leyendo esto es porque no te has negado a continuar<br />

aprendiendo CoffeeScript, ahora vas a ver un nuevo ejemplo que<br />

te hará subir de nivel:


3. Funciones, Ámbito y Contexto 29<br />

divide = (numbers...) -><br />

result = 0<br />

numbers.forEach (number) -> result = result / number<br />

result<br />

Como ves en este ejemplo he introducido el símbolo ... (splats)<br />

detrás del argumento numbers, haciendo que CoffeeScript espere un<br />

numero indeterminado de argumentos y que los vaya dividiendo<br />

y almacenando en la variable result. Veamos esto mismo en<br />

JavaScript:<br />

var divide,<br />

__slice = [].slice;<br />

divide = function() {<br />

var numbers, result;<br />

numbers = 1


3. Funciones, Ámbito y Contexto 30<br />

race = (winner, runners...) -> console.log winner, runn\<br />

ers.join(“,“)<br />

Utilizar un splat en runners hace que CoffeeScript espere un<br />

rango de valores y automáticamente los convierta en un array de<br />

elementos, siempre y cuando existan valores. Como vemos en el<br />

ejemplo continuamos con la declaración de funciones en una única<br />

linea pero si leemos el código en JavaScript el numero de lineas crece<br />

considerablemente:<br />

var race,<br />

__slice = [].slice;<br />

race = function() {<br />

var runners, winner;<br />

winner = arguments[0], runners = 2 # eat it?<br />

Los argumentos que no son de tipo splat se asignarán en primer<br />

lugar, por lo que si se llama a sandwich con dos únicos argumentos,<br />

estos pasarán a top y base. Sólo cuando hay tres o más argumentos<br />

se utilizará el argumento splat ingredients y con esto CoffeeScript<br />

vuelve a reafirmarse con la convención “simplicidad frente a complejidad”.<br />

Recordarte, como buen conocedor de los internals de JavaScript,<br />

que también podríamos no declarar ningún argumento y acceder a<br />

ellos gracias al array arguments:


3. Funciones, Ámbito y Contexto 31<br />

avengers = -> "Hulk, Thor, Ironman, #{arguments[0]}!"<br />

Aprovecho esta función para recordarte la interpolación por medio<br />

de #{} que aprendiste en el capítulo anterior, acostúmbrate a<br />

utilizarla siempre que puedas. Veamos como quedaría la función<br />

avengers en JavaScript:<br />

avengers = function() {<br />

};<br />

return "Hulk, Thor, Ironman, " + arguments[0] + "!";<br />

3.3 Llamando a funciones<br />

Hasta ahora has aprendido como declarar funciones con CoffeeScript,<br />

sin argumentos, con argumentos y has conocido los splats…<br />

aunque todavía no sabes como llamar a las funciones que hemos<br />

escrito. CoffeeScript vuelve a conseguir de una forma muy simple<br />

que nos centremos únicamente en el hecho y no en la forma:<br />

result = divide 1, 2<br />

Como ves no tenemos que utilizar paréntesis ni punto y coma para<br />

declarar el limite de los argumentos de una función, si compilamos<br />

a JavaScript sería:<br />

var result = divide(1, 2);<br />

Podemos concatenar funciones de una manera sencilla, imagina<br />

que no quieres guardar la suma en una variable result y que<br />

únicamente te interesa lanzar un mensaje por tu pantalla gracias<br />

al método de JavaScript alert:


3. Funciones, Ámbito y Contexto 32<br />

alert divide 1, 2<br />

Fíjate como CoffeeScript sabe perfectamente lo que quieres hacer y<br />

compila un JavaScript lleno de complicadas ( y ):<br />

alert(divide(1, 2));<br />

Voy a complicarlo un poco más, imagínate que tenemos una función<br />

que recibe argumentos combinando valores String, Number,<br />

Boolean con Objects. Veamos la f<br />

hero = (year, properties, superpowers) -><br />

hero 1939, name: "Batman", city: "Gotham", false<br />

Como ves llamo a la función sin delimitar la propia función ni<br />

estableciendo las Curly Braces en el objeto properties, pero CoffeeScript<br />

y su magia vuelven a hacer acto de presencia para que la<br />

función hero funcione sin problemas:<br />

var hero;<br />

hero = function(year, properties, superpowers) {};<br />

hero(1939, {<br />

name: "Batman",<br />

city: "Gotham"<br />

}, false);<br />

Todavía no hemos visto como llamar a una función sin argumentos,<br />

y en esta ocasión se hace igual que en JavaScript utilizando nuestros<br />

queridos (sarcasmo) e inseparables paréntesis:


3. Funciones, Ámbito y Contexto 33<br />

hello()<br />

También existe otra forma de llamar a funciones sin argumentos y<br />

es utilizando el alias operador do, el cual utilizo siempre que puedo<br />

ya que le da más expresividad a mi código:<br />

do hello<br />

Ambos ejemplos, como era de esperar, devuelven el mismo JavaScript:<br />

hello();<br />

3.4 Ámbito<br />

Por ahora no hemos controlado el ciclo de vida de nuestras variables,<br />

el ámbito, por desgracia esta despreocupación en JavaScript<br />

nos puede llevar a futuros problemas dentro de nuestra aplicación<br />

web, menos mal que CoffeeScript nos ayudará en este proceso.<br />

Vamos a ver un sencillo ejemplo:<br />

lifes = 0<br />

restartGame = -> lifes = 3<br />

do restartGame<br />

console.log "I have #{lifes} lifes in the game."<br />

> I have 3 lifes in the game.<br />

Como probablemente esperabas, la consola mostrará I have 3<br />

lifes in the game., pero si realizamos un simple cambio,<br />

conmutando las 2 primeras lineas:


3. Funciones, Ámbito y Contexto 34<br />

restartGame = -> lifes = 3<br />

lifes = 0<br />

do restartGame<br />

console.log "I have #{lifes} lifes in the game."<br />

> I have 0 lifes in the game.<br />

Ahora el resultado, sorprendentemente es totalmente diferente I<br />

have 0 lifes in the game.. Curioso, tu función restartGame no<br />

ha tenido ningún efecto sobre la variable lifes. ¿Cómo ha podido<br />

suceder esto? Te voy a mostrar otro ejemplo a ver si eres capaz de<br />

comprender que está pasando:<br />

restartGame = -> lifes = 3<br />

do restartGame<br />

console.log "I have #{lifes} lifes in the game."<br />

> ReferenceError: lifes is not defined<br />

Hemos conseguido generar un error de ámbito de variable, y ahora<br />

te pregunto ¿como puedes saber el alcance de una determinada<br />

variable? Muy fácil su ámbito se define gracias a tres sencillas<br />

reglas:<br />

• Cada función crea un ámbito, y la única manera de crear un<br />

ámbito es definiendo una función.<br />

• El ciclo de vida de una variable perdurará en el ámbito más<br />

externo en el que se ha hecho una asignación a esa variable.<br />

• Fuera de su ámbito, una variable es invisible.<br />

Tomando como ejemplo los anteriores ejemplos, el ámbito de lifes<br />

en el primer ejemplo fue el contexto global (GlobalScope), en el<br />

segundo ejemplo, hubo una variable lifes en el ámbito global


3. Funciones, Ámbito y Contexto 35<br />

y otra en el ámbito de la función restartGame, y en el último<br />

ejemplo, solo existía dentro de la función restartGame. Es por<br />

eso que tenemos un ReferenceError sobre lifes tratando de ser<br />

utilizada fuera de la función restartGame, puesto como habrás<br />

podido descubrir la variable no existe.<br />

En CoffeeScript al ámbito se conoce como ámbito léxico, y realmente<br />

es el mismo que en JavaScript, salvo que en este último la<br />

declaración del ámbito va asociada a la palabra reservada var y en<br />

CoffeeScript el ámbito se define con la primera asignación. Esto<br />

te ahorra tiempo a la hora de desarrollar tu código, pero siempre<br />

siendo responsable y teniendo cuidado ya que puedes provocar<br />

inconscientemente el llamado shadowing de variables que no es otra<br />

cosa que crear variables fuera de su área de uso.<br />

En CoffeeScript solo existen dos maneras de realizar shadowing<br />

a una variable: la primera la hemos visto en el segundo ejemplo<br />

de restartGame, creando una variable junto con otra variable de<br />

ámbito más interno. La otra manera es como argumento de una<br />

función:<br />

lifes = 3<br />

insertCoin = (coins, lifes) -> lifes += coins * 3<br />

console.log insertCoin 3, lifes<br />

> 12<br />

console.log lifes<br />

> 3<br />

Bien vamos a analizar que está pasando con la función insertCoin,<br />

posiblemente pensabas que por cada coin introducida tu vida se iba<br />

a multiplicar por 3 el numero de lifes de tu variable más externa.<br />

Pero has visto que al consultar lifes ves que sigue siendo 3 y no<br />

12 como esperabas. Realmente la respuesta es sencilla, la función<br />

insertCoin genera un nuevo ámbito para lifes puesto que se pasa


3. Funciones, Ámbito y Contexto 36<br />

como parámetro y el cometido de esta operación es únicamente<br />

devolver el resultado de la operación, el cual no se asigna a lifes.<br />

El shadowing normalmente esta considerado un mala praxis en<br />

programación JavaScript y por lo tanto debes intentar evitarlo.<br />

Intenta dar nombres diferentes a tus variables, para no llegar a<br />

confusiones sobre el ámbito de las mismas.<br />

En este punto te preguntarás, “¿Cómo puedo asignar a una variable<br />

el ámbito correcto sin realizar una asignación?” La respuesta es que<br />

en CoffeeScript es imposible. En lugar de eso tendrás que realizar<br />

una asignación tradicional como por ejemplo usando un null o<br />

cualquier otro valor inicial no sensible. He aquí un ejemplo:<br />

hero = null<br />

window.onload = -> hero = "Batman"<br />

3.5 Contexto<br />

Ámbito y contexto están muy relacionados dentro de CoffeeScript,<br />

pero no por ello deben mezclarse los conceptos. Mientras que el<br />

ámbito se preocupa de la variable y el identificador al que hace<br />

referencia, el contexto se preocupa de la palabra reservada this,<br />

y en el caso de CoffeeScript de su alias @.<br />

Los recién llegados al mundo de JavaScript y CoffeeScript a menudo<br />

se encuentran con un desconcertante y poco descriptivo this. Utilizándolo<br />

correctamente, te sientes verdaderamente un verdadero<br />

SuperHeroe dispuesto a salvar al mundo. Usándolo erróneamente,<br />

puede ser sin lugar a duda un enorme foco de errores. Parte de la<br />

confusión deriva en la palabra misma, la gente espera que this hace<br />

referencia a “este objeto”. En su lugar, debes pensar en ello como<br />

“este contexto” y como verás más adelante, el contexto, this/@,<br />

puede ser totalmente diferente cada vez que se llame a una función.<br />

Para los ejemplos utilizaremos un simple método createPower:


3. Funciones, Ámbito y Contexto 37<br />

createPower = (power) -> @power = power<br />

En este caso @power y power son variables totalmente diferentes,<br />

power, que podrías haberla llamado como quisieses, es una variable<br />

local y nunca se verá fuera de la función createPower, mientras que<br />

@power es una propiedad del contexto.<br />

El objetivo principal de contexto es dar a los métodos de un objeto<br />

(en funciones añadidas como propiedades) una forma de referirse<br />

al objeto que está siendo llamado. Veamos otro ejemplo:<br />

hero = {}<br />

hero.createPower = createPower<br />

hero.createPower "Fly"<br />

console.log hero.power<br />

> "Fly"<br />

Cuando llamamos a hero.createPower, realmente estamos llamando<br />

al método createPower que habíamos creado antes con el objeto<br />

hero como contexto; por lo que @ en la función se refiere al objeto<br />

hero, por lo que creará un atributo @name haciendo referencia a<br />

hero.name. La función en si no ha cambiado, y podríamos llamarla<br />

las veces que necesitemos no cambiando por ello el objeto Hero:<br />

createPower "Fury"<br />

console.log hero.power<br />

> "Fly"<br />

Otro ejemplo que podemos realizar es no añadir la función a ningún<br />

objeto en particular y utilizar los métodos call o apply propios de<br />

la función (y qué como sabes todas las funciones JavaScript tienen).<br />

El método apply necesita un contexto y un array de argumentos<br />

para ejecutarse:


3. Funciones, Ámbito y Contexto 38<br />

superman = {}<br />

createPower superman, ["Fly"]<br />

console.log superman.power<br />

> "Fly"<br />

El método call funciona exactamente igual, excepto por que recibe<br />

un solo argumento y no un array. De esta manera apply es mucho<br />

más versátil puesto que puede recibir una lista de argumentos, de<br />

todas formas veamos el equivalente call al ejemplo anterior:<br />

createPower.call superman, "Fly"<br />

Por ultimo veremos otra manera de dar a una función un contexto<br />

y es utilizando la palabra reservada new, el cual creara un nuevo<br />

objeto utilizando la función como constructor:<br />

Power = createPower<br />

heroes[1] = new Power "Fly"<br />

heroes[2] = new Power "Fury"<br />

console.log heroes[1].power<br />

> ”Fly”<br />

console.log heroes[2].power<br />

> "Fury"<br />

Como te estarás dando cuenta la palabra new no está devolviendo<br />

el resultado de la función createPower, en cambio crea un nuevo<br />

objeto, ejecuta la función en el contexto del objeto y tras ello<br />

devuelve el objeto en si. Ahora ya has alcanzado un nuevo nivel<br />

como desarrollador CoffeeScript, vale la pena que repasemos juntos<br />

lo aprendido:<br />

• Cuando utilizas la palabra new delante de una llamada a una<br />

función, el contexto es el nuevo objeto.


3. Funciones, Ámbito y Contexto 39<br />

• Cuando ejecutas una función mediante call o apply, el<br />

contexto es el primer argumento.<br />

• Si una función se llama como una propiedad de objeto<br />

obj.func o obj['func'], se ejecuta en el contexto de ese<br />

objeto.<br />

• Si no es ninguna de las reglas anteriores, la función se ejecuta<br />

en el contexto global.<br />

3.6 Cambio de contexto en funciones<br />

Los cambios de contexto son algo común en JavaScript, especialmente<br />

en los callbacks de eventos, por lo qué CoffeeScript nos<br />

brinda la posibilidad de manejar esta situación muy facilmente.<br />

Lo más común dentro de una función es la variación de -> por la<br />

llamada Flecha Ancha o RocketArrow =>.<br />

Usando => en vez de la Flecha Fina -> te aseguras que el contexto<br />

de la función será el local. Por ejemplo:<br />

el.addEventListener "click", (event) => @handler event<br />

La razón por la que debes utilizar =>, dejando que CoffeeScript<br />

haga todo el trabajo por nosotros, es para que el callback de<br />

addEventListener no se ejecute en el contexto de el y se ejecute<br />

en el contexto local donde esta declarada la sentencia.<br />

Como hace mucho que no ves código JavaScript, te voy a enseñar<br />

la compilación de este ejemplo para que veas que es lo que hace<br />

CoffeeScript:


3. Funciones, Ámbito y Contexto 40<br />

var _this = this;<br />

el.addEventListener("click", function(event) {<br />

});<br />

return _this.handler(event);<br />

Como ves el truco está en crear una variable _this que hace referencia<br />

al @ global, y por lo tanto es accesible desde addEventListener.<br />

En cambio si utilizamos -> el contexto es el de el y no podríamos<br />

acceder a la función handler:<br />

el.addEventListener "click", (event) -> @handler event<br />

el.trigger "click"<br />

> ReferenceError: handler is not defined<br />

Comprueba que en JavaScript ya no existe la variable this:<br />

el.addEventListener("click", function(event) {<br />

return this.handler(event);<br />

});<br />

el.trigger("click");<br />

En este punto terminamos este capítulo, en mi opinión junto con<br />

las Clases (que veremos en un capítulo futuro) el tratamiento de<br />

Funciones es el area más importante de CoffeeScript. Espero que<br />

haya sido de tu agrado y que ahora te sientas capaz de dominar las<br />

funciones en CoffeeScript como nunca lo habías imaginado.


4. Objetos y Arrays<br />

Ya dominas las funciones con CoffeeScript, ahora toca descubrir<br />

como utilizar tus funciones con colecciones de datos: los objetos y<br />

Arrays.<br />

Comenzaremos echando un vistazo a los objetos como una buena<br />

propuesta para almacenar datos. Tras esto aprenderás como utilizar<br />

las listas, las cuales te darán un buen mecanismo para ordenar nuestros<br />

datos. Desde aquí comenzaremos con las estructuras iterativas<br />

loop, las comprensiones y la creación directa de arrays gracias a<br />

ellas. Selección de matrices en base a matching… y mucho mas.<br />

4.1 Recordando JavaScript y sus Objetos<br />

Antes de comenzar con la sintaxis CoffeeScript, será mejor que<br />

demos un breve repaso a los objetos en JavaScript, reconociendo<br />

que casi todo es un objeto; las únicas excepciones son las primitivas:<br />

boolean, number y string y las constantes undefined y NaN. El<br />

objeto más simple se escribiría:<br />

var object = new Object();<br />

Aunque comúnmente se suele utilizar la sintaxis heredada de JSON²³:<br />

var object = {};<br />

Existen muchísimas otras formas de creación de objetos, es más<br />

en el capítulo anterior hemos estado utilizando algunas de ellas,<br />

²³http://json.org


4. Objetos y Arrays 42<br />

puesto que todas las funciones son en si objetos (puesto que no son<br />

ni boolean, number, string, undefined o NaN).<br />

Para acceder a las propiedades de un objeto tenemos dos formas, con<br />

la notación simple . o con la notación tipo bracket {}. La primera es<br />

sumamente sencilla de utilizar: obj.x hace referencia a la propiedad<br />

x del objeto obj. La notación via bracket es mucho más versátil,<br />

puesto que cualquier expresión que se incluya entre los brackets<br />

se evaluará y converirá a un string utilizándose como nombre de<br />

propiedad, veamos el mismo ejemplo obj['x']<br />

Normalmente, utilizarás la notación por punto si conoces el nombre<br />

de la propiedad previamente y en el caso de que lo tengas que<br />

determinar dinámicamente utilizarás la notación por bracket. Pero<br />

no siempre el primer caso funciona:<br />

symbols.* = 'plus' # Falla!!<br />

symbols.['*'] = 'plus'<br />

La primera sentencia falla ya que + esta reservado como operados,<br />

mientras que la segunda sentencia al ser pasada como string no tiene<br />

ese problema. Creo que por ahora no hace falta que recordemos<br />

más particularidades de JavaScript.<br />

4.2 Objetos<br />

Los objetos en CoffeeScript se pueden crear exactamente igual que<br />

en JavaScript, con nuestras queridas Curly Braces y una lista de<br />

declaraciones de Clave/Valor:<br />

numbers = {one: 1, two: 2}<br />

Sin embargo, al igual que en la invocación de funciones, CoffeeScript<br />

nos permite aligerar nuestro código dejándonos a nuestra


4. Objetos y Arrays 43<br />

elección la utilización de los caracteres {}. Personalmente, las quito<br />

siempre y además utilizo el nivel de indentación con las nuevas<br />

lineas como sustituto del separador , de propiedades:<br />

numbers =<br />

one: 1<br />

two: 2<br />

Con la exclusión completa de {} y , conseguimos que nuestro objeto<br />

sea más parecido a un YAML²⁴:<br />

kids =<br />

brother:<br />

name: "Max"<br />

age: 11<br />

sister:<br />

name: "Ida"<br />

age: 9<br />

Este ejemplo seguro que te hará sonreír ademas de ver el verdadero<br />

potencial de la creación de objetos en una linea:<br />

fellowship = wizard: 'Gandalf', hobbits: ['Frodo', 'Pip\<br />

pin', 'Sam']<br />

La magia de CoffeeScript se encuentra en que cada vez que encuentra<br />

el caracter : sabe que estás haciendo referencia a un objeto.<br />

Esta técnica es especialmente útil cuando una función tiene un<br />

argumento que es un objeto:<br />

²⁴http://yaml.org/


4. Objetos y Arrays 44<br />

findPeople latitude, longitude, order: true<br />

Compilando a JavaScript de la siguiente manera:<br />

drawSprite(latitude, longitude, {order: true});<br />

Aunque ya tienes una base de JavaScript, vale recordar el uso de<br />

this en esta ocasión vamos a crear un objeto que tenga una función<br />

toString que devuelva serializado alguna de las propiedades de<br />

nuestro objeto. Veamos como:<br />

podcast =<br />

number : 11<br />

title : '¿Porqué es difícil testear?'<br />

description: 'Conversación con Javier Acero sobre tes\<br />

tear y programar.'<br />

details:<br />

homepage : 'http://www.bastayadepicar.com'<br />

url : 'http://www.bastayadepicar.com/episodio/\<br />

011'<br />

toString: -> "#{@number}. #{@title}"<br />

Como ves existe el caracter @ que realmente hace referencia a this<br />

que como ya sabemos esta marcando que el contexto es el suyo mismo<br />

(dado que es una flecha fina ->). @ no deja de ser un facilitador<br />

más de CoffeeScript. Una de las cosas que siempre recomiendo a la<br />

hora de trabajar con CoffeeScript es ver el código compilado para<br />

analizar las estructuras JavaScript que genera, analicemos pues:


4. Objetos y Arrays 45<br />

var podcast;<br />

podcast = {<br />

number: 11,<br />

title: '¿Porqué es difícil testear?',<br />

description: 'Conversación con Javier Acero sobre tes\<br />

tear y programar.',<br />

details: {<br />

homepage: 'http://www.bastayadepicar.com',<br />

url: 'http://www.bastayadepicar.com/episodio/011'<br />

},<br />

toString: function() {<br />

return "" + this.number + ". " + this.title;<br />

}<br />

};<br />

En JavaScript, no puedes usar palabras reservadas como atributos<br />

de un objeto, por ejemplo class. CoffeeScript si te permite hacerlo<br />

puesto que todos los accesos a las propiedades los realizará por<br />

notación bracket. Veamos el ejemplo module.class = 'atom' el<br />

cual compilado a JavaScript será module['class'] = 'atom';.<br />

Un último apunte sobre objetos en CoffeeScript, recomiendo encarecidamente<br />

el uso de la expresión of para conocer si una propiedad<br />

existe dentro de un determinado objeto:<br />

console.log wizard of fellowship<br />

4.3 Arrays<br />

Los arrays siguen requiriendo los caracteres [] para indicar sus<br />

elementos, por lo que tampoco vas a encontrar mucha diferencia<br />

con JavaScript. De todas formas puedes utilizar la indentación como<br />

delimitador de elementos y podrás finalizar con , algo que en<br />

JavaScript no está permitido y suele dar bastantes quebraderos de<br />

cabeza. Veamos unos ejemplos:


4. Objetos y Arrays 46<br />

numbers = [1, 2, 3]<br />

letters = [<br />

'A'<br />

'B'<br />

'C'<br />

]<br />

axys = [x, y, z,]<br />

Posiblemente pensarás que no puedo hablar mucho más de Arrays,<br />

nada más lejos de la realidad a partir de ahora voy a poner<br />

casos de uso en combinación con funcionalidades de JavaScript y<br />

CoffeeScript.<br />

Obtener el valor máximo de un array<br />

Imagina que tienes un array numérico y te gustaría obtener el valor<br />

máximo, seguramente ahora estarás pensando en una iteracción en<br />

JavaScript, una variable que va quedándose con el mayor numero<br />

y al final de la iteracción (evidentemente) tendrás el mayor. Bien<br />

vamos a hacerlo al estilo CoffeeScript:<br />

Math.max [12, 32, 11, 67, 1, 3]...<br />

Math.max compara todos los argumentos y devuelve el mayor de<br />

ellos. Para convertir un array a argumentos fíjate que utilizo la<br />

elipsis ..., una técnica muy utilizada para pasar un gran numero<br />

de argumentos a una función.<br />

Mapeando Arrays<br />

Imagina, tienes un array de objetos y quieres crear otro array tomando<br />

ese como base. Lo mismo que el caso anterior, posiblemente<br />

te pondrás a hacer iteraciones, acumuladores… Vamos a ver que<br />

puede hacer CoffeeScript por nosotros:


4. Objetos y Arrays 47<br />

movies = [<br />

name: "Batman", year: 1991, hero: true<br />

,<br />

name: "Spiderman", year: 2003, hero: true<br />

,<br />

name: "Superman", year: 1984, hero: true<br />

,<br />

name: "KickAss", year: 2011, hero: false<br />

]<br />

heroes = movies.map (movie) -> movie.name if movie.hero\<br />

is true<br />

Como ves he utilizado la conocida función map que nos permite<br />

hacer operaciones con los elementos de un array. Como puedes<br />

leer, porque una cosa que nos da CoffeeScript es la comprensión sin<br />

conocimiento, en el nuevo array heroes solo existirán los strings<br />

'Superman', 'Batman' y 'Spiderman' ya que estamos filtrando<br />

por la propiedad hero. Como has podido comprobar tambien he<br />

eliminado las Curly Braces, y he marcado la dimensión de cada<br />

objeto, con un nivel de indentación (fijate que la , esta en un nivel<br />

inferior).<br />

Los mapeos son una buena herramienta para manejar transformaciones<br />

más complicadas que la que hemos realizado, más adelante<br />

conocerás otra manera de hacerlo por medio de comprensiones.<br />

Reduciendo Arrays<br />

Imagina, tenemos un array de elementos y nos gustaría hacer algún<br />

tipo de operación por todos los elementos


4. Objetos y Arrays 48<br />

[1,2,3,4].reduce (x, y) -> x + y<br />

> 10<br />

["batman", "superman", "spiderman", "hulk"].reduceRight\<br />

(x, y) -> x + ", " + y<br />

> 'batman, superman, spiderman, hulk'<br />

También podríamos hacer algo más complejo como generar objetos<br />

tomando como referencia una lista de objetos:<br />

heroes =<br />

{ name: 'batman', year: 1988 }<br />

{ name: 'superman', year: 1981 }<br />

{ name: 'spiderman', year: 2012 }<br />

heroes.reduce (x, y) -><br />

x[y.name]= y.year<br />

x<br />

, {}<br />

> { batman: 1988, spiderman: 1981, spiderman: 2012 }<br />

Los métodos reduce y reduceRight se introdujeron en la versión 1.8<br />

de JavaScript, en este caso CoffeeScript nos provee de una manera<br />

natural y simple para utilizarlos.<br />

Rangos de Arrays<br />

Imagina, que tienes que crear un array que contenga una serie numérica.<br />

Deja de hacer más iteraciones y conoce un nuevo operador<br />

en CoffeeScript:


4. Objetos y Arrays 49<br />

numbers = [1..10]<br />

> [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ]<br />

numbers = [10..1]<br />

> [ 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 ]<br />

Cuando escribimos el operador .. CoffeeScript interpreta que necesitamos<br />

una serie numérica entre el primer (1) y el ultimo valor<br />

(10). Si queremos omitir el ultimo valor dentro de la serie tendremos<br />

que utilizar el operador ... como vemos en el siguiente código:<br />

numbers = [1...10]<br />

> [ 1, 2, 3, 4, 5, 6, 7, 8, 9 ]<br />

Filtrando Arrays<br />

Imagina, necesitas filtrar un array por una determinada condición<br />

booleana.<br />

numbers = [1..10]<br />

numbers.filter (number) -> number > 5<br />

En el método filter vemos que define como parámetro una función<br />

en la cual estamos pidiendo que se quede con los números<br />

del array mayores que 5 por lo que tendremos el resultado<br />

[6,7,8,9,10].<br />

Uniendo Arrays<br />

Imagina, necesitas unir dos arrays en una sola y no quieres crear un<br />

iterador, mira que sencillo:


4. Objetos y Arrays 50<br />

numbers_1 = [1, 2, 3]<br />

numbers_2 = [4, 5, 6]<br />

numbers = numbers_1.concat numbers_2<br />

> [1, 2, 3, 4, 5, 6]<br />

Realmente concates una función de JavaScript, pero mucha gente<br />

no la utiliza y es realmente util. La gran diferencia con el método<br />

push es que concat crea un nuevo array y deja los arrays que se<br />

tomaron como base sin modificarse.<br />

4.4 Comprensiones<br />

Como hemos visto anteriormente podemos hacer mapeos de funciones<br />

de una manera muy sencilla, pero CoffeeScript nos da las<br />

comprensiones un tipo de operación que los desarrolladores de<br />

Python podrán reconocerlas fácilmente. Vamos a volver a realizar<br />

un mapeo mediante comprensión de nuestra conocida array heroes:<br />

movies = [<br />

name: "Batman", year: 1991, hero: true<br />

,<br />

name: "Spiderman", year: 2003, hero: true<br />

,<br />

name: "Superman", year: 1984, hero: true<br />

,<br />

name: "KickAss", year: 2011, hero: false<br />

]<br />

heroes = (movie.name for movie in movies when movie.her\<br />

o)<br />

> [ 'Doctor Teeth', 'Janice', 'Sgt. Floyd Pepper', 'Zoo\<br />

t', 'Lips', 'Animal' ]<br />

Como puedes comprobar es más sencillo que utilizar el método map<br />

y sobre todo la creación del array heroes es realmente comprensible<br />

(léelo y dime que no).


4. Objetos y Arrays 51<br />

Si todavía no te he convencido vamos a ver otro ejemplo de dos<br />

maneras, la aburrida y la divertida (jedy-mode). Teniendo un array<br />

heroes:<br />

heroes = ['Batman', 'Spiderman', 'Superman']<br />

Muestro por pantalla unos heroes determinados, pero para ello<br />

escribo 3 lineas de código:<br />

for hero, index in heroes<br />

if index % 2 == 0<br />

console.log(hero)<br />

Ahora vas a hacerlo como un verdadero Jedi, sintiendo la fuerza y<br />

elegancia que ofrece CoffeeScript:<br />

console.log hero for hero, index in heroes when index %\<br />

2 is 0<br />

Como vemos, dentro del for podemos además de tener cada elemento<br />

en hero, podemos saber el indice del mismo como segundo<br />

argumento (en este caso index). Con lo que utilizamos este segundo<br />

argumento para hacer la función de filtrado. Ahora ya puedes ir a tu<br />

consola de CoffeeScript para jugar con tus heroes y comprensiones.<br />

Si todavía no estas impresionado por esta capacidad que tiene este<br />

lenguaje, solo me queda sorprendente con una implementación del<br />

mítico FizzBuzz en una única linea:<br />

fizzbuzz = (['fizz' unless i%3] + ['buzz' unless i%5] o\<br />

r i for i in [1..100])<br />

Esta implementación no es mía, proviene del blog de Ricardo<br />

Tomasi²⁵, el cual recomiendo que le eches un vistazo.<br />

²⁵http://ricardo.cc/


5. Clases<br />

Si lo sé, hablar de clases en JavaScript puede ser algo peligroso dado<br />

que algunos puristas, aquellos que vienen de lenguajes tradicionales<br />

y tipados, no toman en serio al lenguaje padre de CoffeeScript. Tal<br />

vez sea porque JavaScript sea el lenguaje más famoso que utiliza el<br />

paradigma basado en prototipos, y los demás como Cecil, Omega,<br />

MOO… no sean tan conocidos. Sin embargo, las clases son tan utiles<br />

en JavaScript como lo son en otros lenguajes, con CoffeeScript lo<br />

que conseguimos es tener un nivel de abstracción mucho mayor.<br />

Desde este capítulo daremos un pequeño repaso a los prototipos y<br />

nos meteremos de lleno en la creación de nuestras primeras clases<br />

con CoffeeScript, utilizando herencia, poliformismo…<br />

5.1 Prototipos<br />

Antes de comenzar con las clases es necesario recordar como<br />

funciona un lenguaje prototípico como JavaScript, un prototipo<br />

es un objeto del cual otros objetos heredan sus propiedades. Por<br />

ejemplo vamos a crear nuestro objeto Hero el cual tendrá un método<br />

prototípico says, veamos como:<br />

Hero = (@power) -><br />

Hero::says = -> console.log "My superpower it's #{@powe\<br />

r}!"<br />

Comenzamos declarando Hero, recuerda que existe una convención<br />

para que las bases tengan la primera letra en mayúscula, el cual<br />

recibe el argumento power en su constructor, con esto conseguimos<br />

que este variable esté disponible en la instancia que creemos de<br />

Hero. Veamos como queda en JavaScript:


5. Clases 53<br />

var Hero;<br />

Hero = function(power) {<br />

};<br />

this.power = power;<br />

Hero.prototype.says = function() {<br />

return console.log("My superpower it's " + this.power\<br />

+ "!");<br />

};<br />

Simplemente por recordar; un constructor es una función, y en<br />

javascript, toda función es un objeto y como cualquier objeto tiene<br />

propiedades y métodos. Una función, por defecto, tiene una serie<br />

de propiedades, como: length, constructor, prototype y algunos<br />

métodos como: call, apply, entre otros. Cualquier función es<br />

susceptible de convertirse en un constructor, basta con anteponer<br />

el operador new a la llamada de la función.<br />

Ahora vamos a crear un par de superheroes, perdón, un par de<br />

instancias Hero estableciendo a cada una de ellas su superpoder y<br />

llamando al método says:<br />

superman = new Hero "fly"<br />

superman.says()<br />

> 'My superpower it's fly!'<br />

batman = new Hero "a belt with gadgets"<br />

batman.says()<br />

> 'My superpower it's a belt with gadgets!'<br />

Como podías prever cada instancia de Hero dice que tiene un poder<br />

distinto porque el método says hace referencia al atributo power de<br />

cada instancia. Evidentemente podemos acceder al atributo power:


5. Clases 54<br />

superman.power<br />

> 'fly'<br />

Cuando usas new, ocurren varias cosas:<br />

• Se crea un nuevo objeto<br />

• El nuevo objeto recibe el prototipo desde el constructor<br />

• Se ejecuta el constructor con el contexto del nuevo objeto<br />

Veamos un ejemplo diferente, mezclando prototipos con estáticos:<br />

Hero = (@power) -><br />

Hero.count++<br />

@number = Hero.count<br />

@says()<br />

Hero.count = 0<br />

Hero::says = -> console.log "#{@number}. My superpower \<br />

it's #{@power}!"<br />

En este caso ampliamos el constructor de Hero, haciendo que tenga<br />

un contador de instancias contenido en la propiedad count la cual<br />

se incrementará cada vez que se crea una nueva instancia (de<br />

ahí que la sentencia no fallará, si posteriormente declaramos esa<br />

variable). Además creamos un atributo de instancia @number que<br />

nos devolverá el valor interno de Hero.count, la última sentencia<br />

del constructor será llamar automáticamente al método prototípico<br />

says demostrando que todo lo creado funciona. El resultado sería:


5. Clases 55<br />

superman = new Hero "fly"<br />

> '1. My superpower it's fly!'<br />

batman = new Hero "a belt with gadgets"<br />

> '2. My superpower it's a belt with gadgets!'<br />

Resumiendo, cada vez que se ejecuta el constructor de Hero, los<br />

pasos son:<br />

• Se asigna el superpoder a la instancia con el shortcut @ dede<br />

el argument<br />

• Se incrementa el contador de instancias count<br />

• Copia el valor a la propiedad @number<br />

• Ejecuta la función heredada @says<br />

Recuerda que todas las funciones del nuevo objeto se ejecutarán en<br />

el contexto del propio objeto, aunque en el capítulo destinado a funciones<br />

ya aprendiste como cambiar los contextos de las funciones<br />

¿no?.<br />

5.2 Clases<br />

Ahora que ya hemos recordado los prototipos puedo decirte que<br />

las clases en CoffeeScript se basan en ellos. Hay varias bibliotecas<br />

que han intentado acercar el mundo de las clases a JavaScript, pero<br />

desde mi humilde punto de vista no les ha ido muy bien ya que<br />

la sintaxis ha quedado demasiado complicada. Es entonces cuando<br />

llega CoffeeScript al rescate y logra simplificar la creación de una<br />

clase. Ahora vamos a crear nuestra primera clase Hero:<br />

class Hero<br />

Como ves la simpleza es máxima y sobre todo entendible y comparable<br />

con otros lenguajes de programación. Vamos a ver como<br />

quedaría en JavaScript:


5. Clases 56<br />

var Hero;<br />

Hero = (function() {<br />

function Hero() {}<br />

return Hero;<br />

})();<br />

Como vemos, únicamente hemos declarado una nueva clase Hero,<br />

y la diferencia entre la carga de sintaxis entre CoffeeScript y<br />

JavaScript es abismal; espero que ahora me entiendas. CoffeeScript<br />

nos proporciona con eficacia una abstracción de la base prototípica,<br />

permitiéndonos escribir código mucho más conciso, y sin perder<br />

ninguno de los beneficios de los objetos en JavaScript. Ahora<br />

creemos un constructor como en el anterior apartado dedicado a<br />

los prototipos:<br />

class Hero<br />

constructor: (@power) -><br />

superman = new Hero "fly"<br />

superman.power<br />

> 'fly'<br />

Compilándose a JavaScript, y viendo claramente lo mucho que<br />

ganas con CoffeeScript:<br />

var Hero;<br />

Hero = (function() {<br />

function Hero(power) {<br />

this.power = power;<br />

}<br />

return Hero;<br />

})();<br />

var superman = new Hero("fly");


5. Clases 57<br />

superman.power;<br />

> 'fly'<br />

Ahora vas a aprender la diferencia en la declaración entre métodos<br />

estáticos y métodos de instancia o prototípicos, para que puedas<br />

hacer comparaciones vamos a continuar con nuestro ejemplo de<br />

Hero:<br />

class Hero<br />

# static private<br />

_count = 0<br />

constructor: (@power) -><br />

_count++<br />

@says()<br />

# Instance methods<br />

says: -><br />

console.log "#{@number()}. My superpower it's #{@po\<br />

wer}!"<br />

number: -> _count<br />

Como vemos lo primero que hago es crear una variable privada<br />

_count que sea accesible para todo el contexto de la clase Hero.<br />

En el constructor, incremento el contador y llamo a la función<br />

de instancia says. ¿Por qué CoffeeScript sabe que el método de<br />

instancia? muy sencillo porque estamos estableciendo el alias @<br />

indicando que el contexto de trabajo es el del constructor, ergo el<br />

de una instancia.<br />

Para declarar métodos de instancia debes utilizar el operador : junto<br />

con el nombre del método que deseas crear. En nuestra clase hemos<br />

creado 2 métodos: says que muestra por pantalla el numero de


5. Clases 58<br />

instancia y el poder de nuestro hero y number que muestra el valor<br />

de la variable _count.<br />

Ahora imagina que necesitas un método estático para la clase Hero,<br />

por ejemplo vamos a crear un método count que nos de el numero<br />

de instancias creadas hasta el momento:<br />

class Hero<br />

# ... previous code ... #<br />

# static public method<br />

@count: -><br />

console.log "Number of instances #{_count}"<br />

De esta manera ahora según vas creando instancias, podrás llamar<br />

al método count de la clase Hero, el cual solo es accesible desde la<br />

clase y no desde sus instancias:<br />

superman = new Hero "fly"<br />

batman = new Hero "a belt with gadgets"<br />

Hero.count()<br />

> 'Number of instances 2'<br />

5.3 Herencia<br />

La implementación de clases de CoffeeScript no estaría completa<br />

sino hubiese ningún mecanismo de obtener herencia entre clases,<br />

tranquilo CoffeeScript la tiene. Vas a poder heredar de otra clase<br />

simplemente usando el operador extends. En el siguiente ejemplo<br />

vas a ver como crear una clase base Vehicle, de la que extenderemos<br />

los vehículos de nuestros heroes. Suena divertido ¿no? comencemos:


5. Clases 59<br />

class Vehicle<br />

fuel: 100<br />

constructor: (@type, @hero) -><br />

use: -><br />

@fuel--<br />

if @fuel > 0<br />

console.log "#{@hero} is using a #{@type}"<br />

else<br />

console.log "Upps!! No fuel in the tank of #{@con\<br />

structor.name}"<br />

Bien, lo primero que he hecho ha sido crear una variable de instancia<br />

fuel, recuerda :, que contendrá el nivel de gasolina del deposito.<br />

El constructor de nuestra clase Vehicle recibe dos argumentos, type<br />

para indicar el tipo de vehículo y heropara indicar el nombre del<br />

heroe dentro del vehículo. Por último he declarado un método de<br />

instancia use el cual irá restando gasolina y testará el nivel de la<br />

misma para dar un mensaje por consola.<br />

Ahora vamos a crear nuestra primera clase extendida de Vehicle,<br />

así que vamos a coger a Batman y le vamos a meter dentro de su<br />

BatMobile:<br />

class BatMobile extends Vehicle<br />

constructor: -><br />

super "car", "Batman"<br />

Como puedes comprobar lo único que hago a la hora de crear la<br />

clase BatMobile es usar el operador extends haciendo referencia<br />

a Vehicle. Tras esto en el constructor de la nueva clase llamo al<br />

constructor de Vehicle con el método super y los 2 argumentos que<br />

necesita "car" haciendo referencia a @type y "Batman" haciendo<br />

referencia a @hero. Tan sencillo como eso, ahora podemos hacer<br />

que Batman use su vehículo:


5. Clases 60<br />

batmobile = new BatMobile()<br />

batmobile.use()<br />

> 'Batman is using a car'<br />

Ahora voy a crear otro vehículo y voy a sobreescribir la variable<br />

fuel en la nueva clase y así podré ver el diferente comportamiento<br />

del método use:<br />

class BatPod extends Vehicle<br />

fuel: 0<br />

constructor: -><br />

super "moto", "Robin"<br />

Pobre "Robin" cuando vaya a utilizar la nueva clase BatPod no va<br />

a poder usarla:<br />

batpod = new BatPod()<br />

batpod.use()<br />

> 'Upps!! No fuel in the tank of BatPod'<br />

Como ves en el método use de la clase Vehicle utilizo el atributo<br />

@constructor.name que hace referencia al nombre de la clase, en<br />

este caso BatPod. Como queremos que Robin pueda disfrutar de<br />

su vehículo vamos a crear un método de instancia y exclusivo de<br />

BatPod para que recargue la gasolina:<br />

class BatPod extends Vehicle<br />

# ... previous code ... #<br />

refuel: -><br />

@fuel = 10


5. Clases 61<br />

Finalizando este apartado tengo que decir que las propiedades<br />

estáticas se copian en las subclases, en lugar de estar heredadas por<br />

referencia. Esto es debido a la arquitectura e implementación de los<br />

prototipos de JavaScript, y desgraciadamente es un problema difícil<br />

de solucionar.<br />

5.4 Polimorfismo<br />

Uno de los usos interesantes de las clases es el llamado polimorfismo,<br />

un concepto de la programación orientada a objetos el cual podría<br />

decirse que en esencia refiere al comportamiento de los objetos, no<br />

a su pertenencia a una jerarquía de clases (o a sus tipos de datos).<br />

Te voy a refrescar este concepto con un ejemplo muy sencillo:<br />

class Vehicle<br />

constructor: (@fuel = 10) -><br />

burnout: -><br />

throw new Error "I'm a abstract method"<br />

En este caso nuestra clase Vehicle tiene un método abstracto<br />

burnout el cual si intentamos llamarlo desde una nueva instancia<br />

de esta clase nos dará una excepción. Este método se utilizará en las<br />

subclases de Vehicle y nos devolverá el numero de kilómetros que<br />

puede recorrer el vehículo al ejecutar el método:


5. Clases 62<br />

class BatMobile extends Vehicle<br />

constructor: -><br />

super fuel = 50<br />

burnout: -><br />

console.log @fuel / 25<br />

class BatPod extends Vehicle<br />

burnout: -><br />

console.log @fuel / 8<br />

La diferencia entre el BatMobile y el BatPod es únicamente que el<br />

primero establece el argumento fuel con una cantidad de 50. Como<br />

puedes ver cada método burnout realiza diferentes operaciones<br />

puesto que el consumo de los vehículos es distinto.<br />

kmInBurnout = (vehicle) -><br />

unless vehicle instanceof Vehicle<br />

throw new Error "vehicle requires a Vehicle instance\<br />

!"<br />

console.log vehicle.burnout()<br />

kmInBurnout new BatMobile()<br />

> 2<br />

kmInBurnout new BatPod()<br />

> 1,25<br />

La función kmInBurnout lo primero que hace al recibir un argumento<br />

es comprobar que sea una instancia de la clase Vehicle, para<br />

ello se utiliza la expresión instanceof. En el caso de que sea una<br />

instancia válida devolverá por consola el resultado de la función<br />

burnout.


6. Modularización<br />

Uno de los grandes problemas que existe con JavaScript, ergo con<br />

CoffeeScript, es que no importa el numero de ficheros que tengas<br />

tu proyecto. JavaScript solo sabe de lineas y por lo tanto existe la<br />

posibilidad de que El Libre Albedrío haga acto de presencia, creando<br />

estructuras incorrectas, inmantenibles y peligrando el GlobalScope.<br />

Se que esto puede darse en todos los lenguajes de programación,<br />

pero bajo mi punto de vista JavaScript Todos estos problemas crecen<br />

exponencialmente cuando es un equipo el que se enfrenta a un proyecto<br />

en JavaScript/CoffeeScript, tenemos/tienes que solucionarlo.<br />

En este capítulo he intentado reunir algunos puntos interesantes<br />

que tienes que tener en cuenta para tener un código organizado y<br />

mantenible; independientemente del patrón de diseño que utilices.<br />

6.1 Namespacing<br />

Como ya vimos en capítulos anteriores, todas las variables que se<br />

declaran en una función solo existen en el ámbito propio de la<br />

función. Cada nuevo fichero que compila CoffeeScript a su vez<br />

genera una función autoejecutable, con su propio ámbito, y por<br />

lo tanto si tenemos dos ficheros las variables de un fichero no<br />

serán visibles desde el otro, a menos que estén declaradas en el<br />

GlobalScope. Por una parte esta bien pensado ya que a menos que lo<br />

queramos hacer consecuentemente, tu GlobalScope quedará limpio<br />

y sin saber de tus mil y una funciones.<br />

Bien, y ahora te pregunto ¿cómo podemos acceder a esas funciones<br />

y variables que tenemos en módulos separados y fuera del GlobalScope?;<br />

muy sencillo. Debemos declarar una única variable global, en<br />

browsers asignarla al objeto window y en proyectos NodeJS al objeto<br />

global. Veamos como:


6. Modularización 64<br />

(global or window).libjs = {}<br />

Tan sencillo como lo que ves, nos aseguramos que nuestro objeto<br />

libjs va a declararse en entornos browser o NodeJS. A partir de<br />

ahora ya podemos crear nuestros diferentes módulos utilizando el<br />

namespace libjs:<br />

math.coffee<br />

libjs.math =<br />

sum : (a, b) -> a + b<br />

rest: (a, b) -> a - b<br />

# ... #<br />

constants.coffee<br />

libjs.CONST =<br />

MIN_VALUE: 10<br />

MAX_VALUE: 90<br />

class.coffee<br />

class libjs.Hero<br />

Este es un primer acercamiento a como tener organizados tus<br />

fuentes creando un sistema de Namespaces, de todas formas, te<br />

recomiendo que junto al Namespacing deberás utilizar algún patrón<br />

de diseño; siempre adecuado a la naturaleza de tu proyecto.<br />

6.2 Mixins<br />

Los llamados mixins²⁶ no están soportados de forma nativa en<br />

CoffeeScript, por la sencilla razón de que son triviales y cada<br />

²⁶http://en.wikipedia.org/wiki/Mixin


6. Modularización 65<br />

desarrollador hace su propia implementación; algo parecido a lo<br />

que pasa con el patrón MVC (sarcasmo). En el siguiente ejemplo<br />

podemos ver un ejemplo:<br />

extend = (obj, mixin) -><br />

obj[name] = method for name, method of mixin obj<br />

include = (class_reference, mixin) -><br />

extend class_reference.prototype, mixin<br />

include Hero, film: true<br />

(new Hero).film<br />

En este ejemplo declaro extend e include, mientras que el primero<br />

se encarga de sobrecargar propiedades estáticas el segundo se ocupa<br />

de propiedades de instancia. En el ejemplo puedes comprobar<br />

como creo una propiedad de instancia film para indicar si nuestro<br />

superheroe ha tenido una pelcula, por defecto true.<br />

Los mixins son un buen patrón para compartir lógica de negocio<br />

común entre diferentes módulos de tu aplicación. La ventaja de los<br />

mixins es que puedes incluirlo en más de un objeto o clase, mientras<br />

que comparándolo con la herencia de una clase solo puede heredar<br />

de un único origen.<br />

6.3 Extendiendo clases<br />

Una cosa que aprendí cuando lei mi primer libro sobre CoffeeScript,<br />

escrito por Alex MacCaw²⁷, fue que los mixins no son suficientes<br />

ya que no estan muy orientados a objetos. Necesitamos una mejor<br />

manera de integrar mixins en nuestras clases CoffeeScript, y Alex<br />

pensó en crear una clase base Module de la que el resto de clases<br />

extendiensen. La transcribo tal cual el lo pensó:<br />

²⁷http://alexmaccaw.com/


6. Modularización 66<br />

KEYWORDS = ['extended', 'included']<br />

class Module<br />

@extend: (obj) -><br />

for key, value of obj when key not in KEYWORDS<br />

@[key] = value<br />

obj.extended?.apply(@)<br />

@<br />

@include: (obj) -><br />

for key, value of obj when key not in KEYWORDS<br />

@::[key] = value<br />

obj.included?.apply(@)<br />

@<br />

Como vemos crea dos funciones estáticas extend e include las<br />

cuales reciben un objeto, que en este caso será una secuencia de<br />

nombres de función y su función. La función extend se encargará<br />

de generar las funciones estáticas y la función include las funciones<br />

de instancia, facil. Ahora vamos a ponerlo en práctica, imagina que<br />

tienes un modulo que genera IDs aleatorios:<br />

libjs.guid.coffee<br />

libjs.guid =<br />

generate: -><br />

'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace /[xy\<br />

]/g, (c) -><br />

r = Math.random() * 16 | 0<br />

v = if c is 'x' then r else r & 3 | 8<br />

v.toString 16<br />

.toUpperCase()<br />

El módulo libjs.guid y su función generate lo vamos a incluir<br />

dentro una nueva clase Hero extendida de Module, y la vamos a


6. Modularización 67<br />

utilizar en el constructor que se encargará de con cada instancia<br />

tenga un atributo id que lo identifica:<br />

class Hero extends Module<br />

@include libjs.guid<br />

constructor: (@name) -><br />

@id = @generate()<br />

console.log "Instance with id #{@id}"<br />

Parece sencillo no?, vamos a ponerlo en práctica creando un par de<br />

instancias:<br />

batman = new Hero "Batman"<br />

> 'Instance with id 04C1E095-E1B9-475F-9D8D-48BD931AAD0\<br />

4'<br />

superman = new Hero "Superman"<br />

> 'Instance with id 1EC75599-6CA7-490B-B3C1-F68CF468881\<br />

4'<br />

Como vemos la clase Module que pensó Alex McCaw es tremendamente<br />

fácil de implementar y extensible horizontalmente ya que<br />

puedes tener módulos iguales que se incluyen en clases diferentes,<br />

generando un código así mucho más mantenible. Por ponerte un<br />

ejemplo mis proyectos Monocle²⁸ y Atoms²⁹ utilizan la class Module<br />

y utilizan módulos comunes, a pesar de ser proyectos diferentes.<br />

²⁸https://github.com/soyjavi/monocle<br />

²⁹https://github.com/tapquo/atoms


7. Bibliografía<br />

En este capítulo intento reunir toda la documentación que un<br />

CoffeeScripter tiene que leer para convertirse en un mejor desarrollador.<br />

Muchos de los libros que aparecen en esta lista me han<br />

ayudado a escribir este libro y por lo tanto me siento con el<br />

compromiso de obligarte a leerlos a ti también.<br />

• JavaScript: The Good Partspor Douglas CrockFord (Oreilly)<br />

- Comprar³⁰<br />

• Eloquent JavaScriptpor Marijn Haverbeke - Descargar³¹<br />

• The little book of CoffeeScriptpor Alex McCaw (Oreilly) -<br />

Comprar³²<br />

• CoffeeScript: Accelerated JavaScript Developmentpor Trevor<br />

Burnham (The Pragmatic Programmers) - Comprar³³<br />

• CoffeeScript Cookbookpor David Brady & Co. - Online³⁴<br />

• Testing with CoffeeScriptpor Jack Franklin - Descargar³⁵<br />

• Clean Codepor Robert C. Martin (Prentice Hall) - Comprar³⁶<br />

³⁰http://shop.oreilly.com/product/9780596517748.do<br />

³¹http://eloquentjavascript.net/<br />

³²http://shop.oreilly.com/product/0636920024309.do<br />

³³http://pragprog.com/book/tbcoffee/<strong>coffeescript</strong><br />

³⁴http://<strong>coffeescript</strong>cookbook.com/<br />

³⁵https://efendibooks.com/minibooks/testing-with-<strong>coffeescript</strong><br />

³⁶http://www.amazon.es/Clean-Code-Handbook-Software-Craftsmanship/dp/<br />

0132350882

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!