Sunteți pe pagina 1din 74

CoffeeScript

Un pequeo gran libro

Javi Jimenez
Este libro est a la venta en http://leanpub.com/coffeescript

Esta versin se public en 2013-12-17

This is a Leanpub book. Leanpub empowers authors and


publishers with the Lean Publishing process. Lean Publishing is
the act of publishing an in-progress ebook using lightweight tools
and many iterations to get reader feedback, pivot until you have
the right book and build traction once you do.

This work is licensed under a Creative Commons


Attribution-NonCommercial-NoDerivs 3.0 Unported License
Twitea sobre el libro!
Por favor ayuda a Javi Jimenez hablando sobre el libro en Twitter!
El hashtag sugerido para este libro es #librocoffeescript.
Descubre lo que otra gente est diciendo sobre el libro haciendo
click en este enlace para buscar el hashtag en Twitter:
https://twitter.com/search?q=#librocoffeescript
Dedicado a todas las personas que me sufren da a da.
ndice general

Agradecimientos . . . . . . . . . . . . . . . . . . . . . . . . 1

Prefacio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
JavaScript, El lenguaje padre . . . . . . . . . . . . . . . . 3
CoffeeScript, El hijo bastardo . . . . . . . . . . . . . . . 4
Un libro por el mundo . . . . . . . . . . . . . . . . . . . 5

1. Comenzando . . . . . . . . . . . . . . . . . . . . . . . . 7
1.1 Entorno necesario . . . . . . . . . . . . . . . . . . . . 7
1.2 Instalando NodeJS . . . . . . . . . . . . . . . . . . . . 8
1.3 Instalando CoffeeScript . . . . . . . . . . . . . . . . . 11

2. Sintaxis . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
2.1 Valores, variables y comentarios . . . . . . . . . . . . 13
2.2 Interpolacin de cadenas . . . . . . . . . . . . . . . . 15
2.3 Control de flujo . . . . . . . . . . . . . . . . . . . . . 16
2.4 Loops . . . . . . . . . . . . . . . . . . . . . . . . . . 18
2.5 Alias y Operadores . . . . . . . . . . . . . . . . . . . 22

3. Funciones, mbito y Contexto . . . . . . . . . . . . . . 26


3.1 Funciones . . . . . . . . . . . . . . . . . . . . . . . . 26
3.2 Funciones y Argumentos . . . . . . . . . . . . . . . . 27
3.3 Llamando a funciones . . . . . . . . . . . . . . . . . . 31
3.4 mbito . . . . . . . . . . . . . . . . . . . . . . . . . . 33
3.5 Contexto . . . . . . . . . . . . . . . . . . . . . . . . . 36
3.6 Cambio de contexto en funciones . . . . . . . . . . . 39
NDICE GENERAL

4. Objetos y Arrays . . . . . . . . . . . . . . . . . . . . . . 41
4.1 Recordando JavaScript y sus Objetos . . . . . . . . . . 41
4.2 Objetos . . . . . . . . . . . . . . . . . . . . . . . . . . 42
4.3 Arrays . . . . . . . . . . . . . . . . . . . . . . . . . . 45
4.4 Comprensiones . . . . . . . . . . . . . . . . . . . . . 50

5. Clases . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52
5.1 Prototipos . . . . . . . . . . . . . . . . . . . . . . . . 52
5.2 Clases . . . . . . . . . . . . . . . . . . . . . . . . . . 55
5.3 Herencia . . . . . . . . . . . . . . . . . . . . . . . . . 58
5.4 Polimorfismo . . . . . . . . . . . . . . . . . . . . . . 61

6. Modularizacin . . . . . . . . . . . . . . . . . . . . . . . 63
6.1 Namespacing . . . . . . . . . . . . . . . . . . . . . . 63
6.2 Mixins . . . . . . . . . . . . . . . . . . . . . . . . . . 64
6.3 Extendiendo clases . . . . . . . . . . . . . . . . . . . 65

7. Bibliografa . . . . . . . . . . . . . . . . . . . . . . . . . 68
Agradecimientos
Escribir un libro en estos tiempos tan sumamente acelerados supone
un gran esfuerzo. Principalmente necesitas tiempo y normalmente
la gente no est dispuesta a drtelo; es por eso que doy las gracias
a todas esas personas que me han permitido gastar mi tiempo en lo
que hoy considero importante.
Dar las gracias a mi familia por siempre haberme permitido tener
la libertad que he necesitado para poder equivocarme, conocerme
y ser la persona que hoy soy.
Dar las gracias al equipo de Tapquo: Ina, Cata, Oihane, Janire y
Joseba por continuar con el da a da de nuestra loca empresa y
seguir con el propsito que nos hemos marcado juntos.
Dar las gracias a accionistas, consejeros y amigos de Tapquo por
confiar en mi y darme la libertad para escaparme del pas y
centrarme en este texto que ahora lees.
Dar las gracias tambin a Jeremy Ashkenas por crear el lenguaje
CoffeeScript y contribuir altruistamente a la evolucin del mundo
web, sin olvidar a los numerosos contribuyentes al proyecto, y a
otros proyectos OpenSource, que por suerte son demasiados para
nombrarlos uno a uno aqu.
Por ltimo quiero darte las gracias a ti, gracias por descargarte
este libro y darme una oportunidad de contarte lo que ha supuesto
CoffeeScript en mi vida. Lo mucho que nos ha ayudado dentro de
Tapquo creando un mejor cdigo, ms mantenible y ms comprensi-
ble. Ahora solo te pido una ltima cosa, comparte este libro cmo lo
he hecho yo contigo, reglalo y aydame a transmitir este contenido
por el mundo.
http://tapquo.com
Prefacio
Tal vez no sabes muy bien porqu ests leyendo este pequeo libro
sobre CoffeeScript, antes de nada piensa en este libro como un
regalo que te ofrezco, no espero nada a cambio, nicamente que
disfrutes con su lectura tanto como yo he disfrutado escribindolo.
Te preguntars por qu he decidido escribir un libro en castellano
sobre CoffeeScript, y no sobre JavaScript como muchos esperaban
que hiciera. Razones tengo muchas pero la principal es que tal
vez sea el lenguaje con el que ms me he divertido mientras lo
descubra y el que ms me ha ayudado a mejorar mis capacidades
como desarrollador web. No te puedes hacer una idea lo que ha
supuesto CoffeeScript para mi y por lo tanto para la empresa que
fund, Tapquo. Quiero contarte mis inicios con este maravilloso
lenguaje y tambin su propia gnesis, comencemos.
La primera vez que escuch de CoffeeScript fue gracias a mi amigo
Guillermo Pascual cuando en Septiembre del 2011 estbamos en la
primera oficina de Tapquo desarrollando, y refactorizando, lo que
iba a ser la primera versin de LungoJS. Al principio no le prest
mucha atencin a CoffeeScript, pretenda ser mejor programador
en JavaScript y Lungo iba a ser mi primer gran exponente, tenia
puesto el Focus y no deba dispersarme con eso que nos gusta tanto
a los Developers; aprender un nuevo lenguaje.
Fue en Junio del 2012, una vez que Lungo ya era estable y yo ya
dominaba JavaScript como pretenda, cuando dediqu mi tiempo
a CoffeeScript. Comenc leyendo varios libros, tampoco haba
muchos ms, los cuales me han ayudado a escribir el libro que
http://tapquo
http://twitter.com/pasku1
http://lungo.tapquo.com
Prefacio 3

estas ahora leyendo. Enseguida obtuve el Flow con el lenguaje, ya


que como proscrito Rubista y actual adorador de Python, tanto la
sintaxis como las estructuras me resultaban muy familiares. Tanto
es as que en dos semanas de estudio me decid a crear un micro
Framework MVC, Monocle, el cual intentaba aprovechar lo mejor
de CoffeeScript y que actualmente adems de usarlo activamente
en nuestros locos das de oficina lo usan miles de desarrolladores
por todo el mundo.
Solo me queda pedirte una cosa, divirtete!, divirtete aprendiendo
este lenguaje lleno de buenas intenciones y de alguna que otra
sorpresa.

JavaScript, El lenguaje padre

Si recibiese un BitCoin por cada vez que oigo que JavaScript no es


un gran lenguaje ahora mismo tendra un buen puado de monedas
virtuales en mi bolsillo. JavaScript nunca ha sido, ni ser, el lenguaje
de programacin ms utilizado y ms famoso del mundo, para eso
tenemos a C o Java. Voy a ponerte en contexto, fue desarrollado
en apenas 10 das por el genio Brendan Eich con la nica premisa:
tener una sintaxis muy parecida al lenguaje C, y esa es la nica simi-
litud con el lenguaje C. Como rezan algunos cualquier parecido con
la realidad es pura casualidad y es por eso que desde sus inicios el
nombre ha generado muchas equivocaciones, confundiendolo con
una versin ligera de Java para la web.
Lo que es seguro es que desde sus inicios en 1995 JavaScript ha
seguido en constante evolucin:

1995 Primera versin


1998 ECMA-262 1st + 2nd edition
https://en.wikipedia.org/wiki/Python_(programming_language)
http://monocle.tapquo.com
https://en.wikipedia.org/wiki/Brendan_Eich
Prefacio 4

2000 ECMA-262 3rd edition



2005 AJAX, Array Extras, string generics (v1.5)
2006 Iterators, Pythonic generators (v1.6)
2008 Generator expressions, expression closures, JSON support(v1.7-
v1.8)

2010 EcmaScript5 (v1.8.2)

2014 EcmaScript6

El gran problema que ha tenido JavaScript es que la forma de


desarrollar nunca ha sido comprendida ni para los desarrolladores
de la vieja escuela (C, Java), que se quejaban de la falta de clases y
dems singularidades de la OOP, ni para los que solo han trabajado
con lenguajes modernos (Python, Ruby, Haskell), que maldecan
la verbosidad barroca, con las conocidas llaves, parntesis y puntos
y comas. Por lo tanto siempre ha sido criticado y en mi opinin
siempre lo ser. Como todos los lenguajes, JavaScript tiene defectos,
pero poco a poco y con cada nueva revisin se van puliendo y
mejorando.
En este libro vamos a acercarnos a JavaScript por medio de Cof-
feeScript, pretendo que seas mejor desarrollador JavaScript de lo
que has sido hasta ahora. Mi propsito es que respetes al Lenguaje
Padre y que puedas enfrentarte a proyectos con las suficientes lineas
de cdigo que asuste al mejor de los Gurus de jQuery (sarcasmo).

CoffeeScript, El hijo bastardo

CoffeeScript es un lenguaje de programacin el cual es capaz de


compilar su resultado a JavaScript, es unicamente eso. Est total-
mente inspirado en la sintaxis de lenguajes como Ruby, Python y
http://jquery.com
Prefacio 5

Haskell para capacitar a JavaScript de una expresividad y brevedad


que por si solo no tiene. Tus programas en JavaScript se escribirn
con menos lineas de CoffeeScript, mas o menos una proporcin
1/3, sin tener ninguna perdida de rendimiento (incluso a veces la
mejora).
Su autor es Jeremy Ashkenas y comenz con el proyecto el 13
de Diciembre del 2009 con un misterioso e intrigante comenta-
rio en su primer commit en GitHub "initial commit of the
mystery language". Comenz creando el compilador en Ruby
pero en apenas 3 meses cambio de idea e hizo que el compilador
estuviese escrito con su propio lenguaje, CoffeeScript. El proyecto
pronto fue seguido por multitud de desarrolladores en GitHub,
donde tanto Jeremy como el resto de contribuyentes aadan nuevas
caractersticas cada mes.
Despus de publicarse la versin 1.0 en navidades del 2010, CoffeeS-
cript se convirti en uno de los proyectos ms seguidos en GitHub.
El lenguaje volvi a tener un empujn en la escena web, cuando en
Abril del 2011 David Heinemeier Hansson confirm los rumores
que decan que CoffeeScript iba a estar incluido en la versin 3.1 de
Ruby on Rails.
Y yo me pregunto como puede ser que un lenguaje tan pequeo
haya captado tanto inters? Tres razones me vienen a la mente:
divertido, seguro y fcil de leer.

Un libro por el mundo

Este libro fue escrito durante mi viaje por Tailandia, en los meses
de Noviembre y Diciembre del ao 2013. Decid irme a 12.000km
de mi lugar de residencia para centrarme en el libro y poder dar
lo mejor de mi en l. Uno de mis propsitos en la vida es ofrecer
https://en.wikipedia.org/wiki/Jeremy_Ashkenas
https://github.com/jashkenas/coffee-script
https://en.wikipedia.org/wiki/David_Heinemeier_Hansson
Prefacio 6

mi conocimiento a todo aquel que quiera adquirirlo y esta es una


buena manera de hacerlo. Ahora t tienes que ayudarme a regalar
este libro a tus amigos, no te ha costado nada y no te costar nada
hacerlo.
Mi prximo libro tratar sobre EcmaScript 6 y lo escribir en
Nueva Zelanda, por lo que si despus de leer este libro te ha gustado
tanto como para hacer una donacin, financiando as parte del
prximo libro, te estar eternamente agradecido.
https://en.wikipedia.org/wiki/ECMAScript
leanpub.com/coffeescript
1. Comenzando
Si has leido el prefacio, se puede decir que ya conoces el origen de
CoffeeScript, que es lo que trae y porque es una de las mejores cosas
que le han pasado a los programadores web en estos ltimos aos.
Ahora mismo no eres capaz de escribir una sola linea, as que te voy
a ayudar a preparar tu entorno de trabajo con CoffeeScript.

1.1 Entorno necesario

En el prefacio has aprendido que el compilador de CoffeeScript esta


escrito en CoffeeScript. Curiosidades aparte, tienes que ser capaz de
resolver la siguiente cuestin:
Cmo puedo ejecutar el compilador en mi sistema si todavia
no tengo el compilador de CoffeeScript?
No? Te voy a ayudar a encontrar la solucin preguntndote de
nuevo; si hubiera una manera de ejecutar JavaScript en tu maquina
sin utilizar un navegador web y mostrar el codigo al sistema
operativo Sigues sin caer? De verdad?
Es muy sencillo, no hace falta ms que utilizar NodeJS y he
aqu donde viene un punto de aclaracin; mucha gente entiende
Node como un servidor web en JavaScript pero, por suerte, es
mucho mas que eso y cada vez est ms presente en soluciones
que nada tienen que ver con el mundo de los servidores web.
Fundamentalmente NodeJS es un puerta entre tu codigo JavaScript
y el sistema operativo, trayendo consigo una potente herramienta
llamada NPM, Node Package Manager, que lo hace extensible
http://nodejs.org
http://npmjs.org
1. Comenzando 8

infinitamente. Si vienes del mundo de Ruby piensa en NPM como


una analogia a las Gems.
El resto de este rea se centrar en como instalar NodeJS, que por
supuesto necesitaremos para usar CoffeeScript y su compilador.
Pero si no puedes esperar mas y quieres intentar codificar tus
primeras lineas en CoffeScript echa un pequeno vistazo al Try
CoffeeScript de la pgina oficial.

1.2 Instalando NodeJS

Existen dos formas de instalar nodeJS, mediante el cdigo fuente


del proyecto (y su posterior compilacin) o bien descargando una
instalacin con el proyecto ya compilado. Independientemente del
sistema operativo que uses no tendrs grandes problemas, pero si
que puedo decir que por mi experiencia los que ms problemas
suelen tener con la instalacin han sido los usuarios de Linux.
Veamos como instalarlo en cada uno de los sistemas operativos:

Mac

Si eres usuario como yo del maravilloso Brew (homebrew package


manager), unicamente tendrs que ejecutar el comando:

brew install node

En caso contrario sigue los siguientes pasos:

Instala Xcode
Instala GIT
Ejecuta los siguientes comandos:

http://coffeescript.org
http://brew.sh/
1. Comenzando 9

darwin_setup.sh
git clone git://github.com/ry/node.git
cd node
./configure
make
sudo make install

Linux (Ubuntu)

Antes de compilar NodeJS necesitamos aadir las siguientes depen-


dencias a tu sistema:

sudo apt-get install g++ curl libssl-dev apache2-utils


sudo apt-get install git-core

Ahora ejecuta los mismos comandos que en la instalacin en Mac:

ubuntu_setup.sh
git clone git://github.com/ry/node.git
cd node
./configure
make
sudo make install

Windows

Justo para este sistema voy a recomendar encarecidamente el uso de


los downloads oficiales desde la seccin de descargas de NodeJS.
El cual lo nico que te pedir es reiniciar el sistema para que NodeJS
est disponible.
http://nodejs.org/download/
1. Comenzando 10

Tu primer servidor NodeJS

Vamos a crear un pequeo programa para comprobar que todo


est funcionando correctamente, antes de ello ejecuta el siguiente
comando para comprobar la versin de la que dispones:

node -v

Ahora viendo que tienes una versin reciente (por tu bien) vas a
crear un pequeo servidor con un nico fichero, a este le llamaras
hello_node.js:
hello_node.js

var http = require('http');

http.createServer(function (request, response) {


response.writeHead(200, {'Content-Type': 'text/plain'\
});
response.end('Hello Node.js\n');
}).listen(1337, "127.0.0.1");

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

Ahora toca ver si el servidor arranca correctamente ejecutando el


NCL (Node Command Line):

node hello_node.js

Si todo va bien deberas ver por tu pantalla el mensaje Server


running at http://127.0.0.1:1337/, si es asi vete a tu browser
a esa misma direccin y aparecer por pantalla un bonito mensaje.
Desde este momento puedo decirte que tienes NodeJS listo y fun-
cionando para empezar con CoffeeScript.
1. Comenzando 11

1.3 Instalando CoffeeScript

Ahora que ya tenemos NodeJS la instalacin de nuestro nuevo


lenguaje favorito va a ser sencilla ya que utilizaremos NPM con
el comando:

sudo npm install -g coffee-script

Como ves he puesto sudo (solo para mac/linux) y los parmetros


install (evidente) y -g para que lo instale globalmente seguido de
coffee-script que en este caso es el paquete que queremos instalar.
Tras la instalacin debes comprobar que versin de CoffeeScript
tienes en el sistema:

coffee -v

Si aparece una nueva versin de CoffeeScript la actualizacin


es relativamente sencilla ya que nicamente tienes que volver a
utilizar NPM cambiando un nico parmetro ya sabes cual es?:

sudo npm update -g coffee-script

Ahora que ya tienes CoffeeScript vamos a ver si funciona todo


correctamente creando una simple funcin desde el terminal con
la consola coffee:

coffee
1. Comenzando 12

coffee> sum = (a, b) -> a + b


coffee> sum 1, 2
3
coffee> sum 3, 4
7

Se que no sabes lo que has escrito, no es la idea de este captulo,


aunque por la sintaxis y los operadores puedes llegar a sacar una
conclusin. En el siguiente capitulo vas a conocer ms de la sintaxis
de este lenguaje y descubrirs lo bien hecho que est y lo divertido
que es programar con el.
2. Sintaxis
Antes de comenzar con este captulo asumo que tienes una base en
JavaScript, y eso no quiere decir que sabes usar jQuery o cualquier
otra librera. Sino es as te recomiendo que estudies el Lenguaje
Padre antes de comenzar con el hijo bastardo. De una manera u otra
mi responsabilidad como desarrollador JavaScript es recomendarte
que al menos conozcas, leas y comprendas estos dos libros:

JavaScript, the good parts (Douglas Crockford)


Eloquent JavaScript (Marijn Haverbeke)

En ellos descubrirs algunas particularidades del lenguaje JavaS-


cript y siempre te vendr bien tenerlos a mano para poder repasar
algn que otro concepto. En este captulo vamos a aprender la
sintaxis bsica de CoffeeScript comprobando que comparte ms
similitudes con Ruby o Python que con JavaScript.

2.1 Valores, variables y comentarios

La creacin y asignacin de variables no difiere mucho de otro len-


guaje de programacin, tal vez la mayor diferencia con JavaScript
es que no hace falta comenzar con var ni finalizar la declaracin
con el prehistrico caracter ;. Veamos un ejemplo sencillo:

http://www.amazon.com/JavaScript-Good-Parts-Douglas-Crockford/dp/0596517742
http://eloquentjavascript.net/
2. Sintaxis 14

heroe = "Superman"
year = 1984

Sencillo no?, en el siguiente captulo conocers como CoffeeScript


gestiona automticamente el mbito de nuestras variables, escapan-
do del temido e ineficiente GlobalScope.
En el caso de que necesites introducir cadenas de texto de mayor
tamao podramos hacerlo de la siguiente manera:

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


ing it wrong."
crockford[2] = "JavaScript doesn't suck!
You're just doing it wrong."

Aunque parezca increble los 2 elementos del array crockford


tienen el mismo contenido, y a pesar de que en la segunda parece
que hemos hecho un salto de linea, CoffeeScript y su parseador
darn en ambos casos como resultado:

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

En el caso de que quieras generar un salto de linea te recomiendo


que utilices el delimitador de string """ en vez de utilizar las
prehistricas concatenaciones de \n y \r:

crockford[3] = """
JavaScript doesn't suck!
You're just doing it wrong."""

El resultado de crockford[3] ser:


2. Sintaxis 15

> 'JavaScript doesn't suck!


You're just doing it wrong.'

Los comentarios dentro de nuestro cdigo siguen el mismo patrn,


utilizando el carcter # como delimitador:

# Tu primer comentario

Los comentarios multilinea tambin estn soportados, y como te


puedes imaginar vas a tener que triplicar el caracter # para que sean
efectivos:

###
Un comentario multilinea,
por ejemplo definir la licencia
o autor del cdigo fuente.
###

2.2 Interpolacin de cadenas

CoffeeScript nos da la interpolacin de string de una manera


similar a como lo hace Ruby. Dentro de una cadena delimitada por
el caracter " podremos introducir la expresin #{}, la cual puede
contener cualquier tipo de expresin que ser interpolada a string:

hero = "Batman..."

chat = """
friend : What... is your favorite hero?
soyjavi: #{hero}
friend : Seriously?"""

Vamos a ver ahora un ejemplo algo ms completo con operaciones


numricas donde descubrirs algo ms de mi:
2. Sintaxis 16

born = new Date(1980, 4, 10)


now = new Date().getFullYear()

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


now has #{now - born.getFullYear()} years old\
."

En mi opinin la interpolacin es una solucin mucho ms elegante


que la concatenacin a base de ir anidando strings, variables y el
caracter +.

2.3 Control de flujo

En este apartado vas a ver las estructuras para el control del


flujo de tu aplicacin, recordando que CoffeeScript esta lleno de
convenciones que facilitan la escritura de buen cdigo. Por ejemplo,
no es necesario utilizar parntesis en las expresiones if, else, for,
ni delimitar el mbito del flujo con las aburridas Curly Braces {}.
Veamos un ejemplo:

if year == 1980
born = true
else
born = false

En este caso vemos que el mbito del if lo marca el nivel de


indentacin donde solo hay una linea born = true, aunque
podras introducir todas las que necesites, adems vemos que no
es necesario introducir () y {}. Se recomienda que cada nivel de
indentacin sea de 2 espacios, aunque hay desarrolladores que
utilizan 4 espacios no es muy recomendable ya que con cada nivel
perdemos espacio para escribir nuestro cdigo. De todas formas,
podemos hacerlo de una forma ms elegante, expresiva y en una
sola linea de la siguiente manera:
2. Sintaxis 17

if year is 1980 then born = true else born = false

Como ves en este caso he introducido el alias operador is que


es traducido a JavaScript como ===. En ambos casos el cdigo
resultante en JavaScript ser el mismo, pudiendo comprobar que
esta lleno de todos esos caracteres y convenciones de las que
queremos escapar:

var born;
if (year === 1980) {
born = true;
} else {
born = false;
}

Otra manera de hacer la misma operacin seria utilizando un


operador ternario:

born = (if year is 1980 then true else false)

Traduciendose a JavaScript de una forma bastante similar:

born = (year === 1980 ? true : false);

Ahora sigamos con alguna expresin ms, por ejemplo en el caso


de que solo necesites hacer una comparacin if podramos hacerlo
al estilo Ruby:

born = true if year is 1980

Si quisisemos hacer la negacin de la sentencia anterior, esto


es; establecer la variable born a false, podramos utilizar el alias
operador isnt que se traduce en JavaScript a !==. Veamos como:
2. Sintaxis 18

born = false if year isnt 1980

o tambin utilizando la expresin unless:

born = false unless year is 1980

En ambos casos puedes ver que el JavaScript resultante es el mismo:

var born;
if (year !== 1980) {
born = false;
}

Ya hemos visto los alias is, unless y isnt ms adelante podrs


conocer ms alias disponibles en CoffeeScript los cuales aportarn
una mayor expresividad a tu cdigo.

2.4 Loops

Una de las estructuras que ms solemos utilizar como desarrolla-


dores son las iteraciones o bucles, esto se expone claramente en los
proyectos JavaScript donde al no existir muchos mtodos dedicados
para el tratamiento de arrays debemos leer el contenido de los
mismos de forma iterada.
En CoffeeScript vas a empezar por lo bsico, pero en captulos
posteriores podrs ver que disponemos de hacks dedicados a los
arrays los cuales te solventarn la vida. Vamos a ver como podras
crear un simple bucle contador con la expresin while:
2. Sintaxis 19

heroes = 0
while heroes <= 12
heroes++

En mi opinin prefiero, siempre que el caso lo permita, hacer este


tipo de sentencias en una linea, respetando por todas las cosas el
Clean Code de Uncle Bob, utilizando al igual que en los if la
expresin then:

heroes = 0
while heroes <= 12 then heroes++

Tambin podemos utilizar la expresin until para hacer llegar al


mismo resultado y tal vez dandole mayor expresividad a nuestro
cdigo:

heroes = 0
until heroes is 12 then heroes++

Si por el contrario quieres recorrer un Array (ms adelante dedicar


una seccin completa a los Arrays) deberemos utilizar la expresin
for combinndolo con el operador in de la siguiente manera:

heroes = ["Batman", "Spiderman", "Superman"]


for hero in heroes
console.log hero

Como puedes ver recorremos el array de heroes y cada uno de ellos


ser mostrado en la consola. En el caso de que no quisieses recorrer
todos los heroes, puedes decidir el tipo de incremento que queremos
utilizando la expresin by seguido del incremento numrico:

https://en.wikipedia.org/wiki/Robert_Cecil_Martin
2. Sintaxis 20

heroes = ["Batman", "Spiderman", "Superman"]


for hero in heroes by 2
console.log hero

Con el incremental by 2, el resultado ser:

> "Batman", "Superman"

Al igual que con las estructuras if, while, until podemos resolver
el anterior ejemplo en una nica y expresiva linea:

console.log hero for hero in ["Batman", "Spiderman", "S\


uperman"] by 2

Ahora voy a complicarlo un poco ms, filtrando el array por un


determinado condicionante; en este caso nos vamos a quedar con
los heroes que tengan como inicial la letra S:

heroes = ["Batman", "Spiderman", "Superman"]


console.log hero for hero in heroes when hero[0] is "S"

Quiero que leas el cdigo resultante en JavaScript, para comprobar


que las estructuras que genera CoffeeScript son totalmente correc-
tas, respetando declaracin y mbito de variables:
2. Sintaxis 21

var hero, heroes, _i, _len;


heroes = ["Batman", "Spiderman", "Superman"];
for (_i = 0, _len = heroes.length; _i < _len; _i++) {
hero = heroes[_i];
if (hero[0] === "S") {
console.log(hero);
}
}

En el caso de que necesites de estructuras iterativas abiertas, lo


mejor es que utilices la expresin loop. La cual nos da un mayor
control sobre el flujo de control de nuestro bucle ya que siempre
est iterando hasta que se cumpla algn condicionante dentro de el
y demos por finalizo el proceso con la expresin break. Veamos un
ejemplo:

heroes = 2
loop
break if heroes is 8
heroes++
console.log heroes

Como puedes leer el bucle terminar cuando la variable heroes sea


igual a 8, ya que la expresin break ejecuta la linea inmediata a
la estructura loop. Vamos a echar un vistazo a como quedara el
cdigo en JavaScript:
2. Sintaxis 22

var heroes = 2;
while (true) {
if (heroes === 8 {
break;
}
heroes++;
}
console.log(heroes);

2.5 Alias y Operadores

Ya sabes que una de las premisas de CoffeeScript es intentar crear


cdigo expresivo, por ahora hemos visto algunos operadores como
is, isnt, unless y desde esta seccin conoceremos ms facilitadores
para nuestro cdigo CoffeeScript.
Como ya sabes is es traducido al comparador === y su contrario
isnt es traducido a !==, en el caso de que quieras hacer una
negacin ! debers utilizar el operador not. Veamos un ejemplo:

facebook_account = false
if not facebook_account
console.log "Well done!!"

Ahora quiero hacerte una pregunta Como lees en lenguaje natural


los operadores en JavaScript || y &&?, me imagino que la respuesta
que te habrs dado a ti mismo ha sido or y and. Bien, pues
CoffeeScript intenta crear lenguaje natural en tu cdigo facilitando
que cualquier persona pueda entender lo que pretendes hacer con
el. Veamos un ejemplo:
2. Sintaxis 23

facebook_account = false
twitter_account = false
if not facebook_account and not twitter_account
console.log "You're a caveman."

El operador or tambin puedes utilizarlo para inicializar variables


con valores por defecto. Pongamos el caso de que queremos alma-
cenar en la variable where el valor de location solo cuando este
sea distinto de undefined, en caso contrario establecemos el valor
string "Gotham"

where = location or "Gotham"

El operador existencial ? puede ayudarnos a que el ejercicio anterior


sea ms preciso, dado que si la variable location no esta declarada
dar un error de compilacin. Utilizando ? nos aseguramos que
comprueba que location no sea ni undefined ni null:

where = location ? "Gotham"

Veamos como queda esta mnima sentencia en JavaScript:

var where;
where = typeof location !== "undefined" && location !==\
null ? location : "Gotham";

El operador existencial ? te puede servir para muchos ms con-


textos, por ejemplo imagina que tienes una librera basada en
mdulos y quieres llamar a un mtodo solo si existe un determinado
namespace:
2. Sintaxis 24

batman.vehicles?.batMobile()

Aqu vemos algo de la magia de CoffeeScript, en el caso de que la


propiedad vehicles de batman no exista, no ejecutar el mtodo
batMobile. Traduciendo la anterior sentencia a JavaScript quedara
de la siguiente manera:

var _ref;
if ((_ref = batman.vehicles) != null) {
_ref.batMobile();
}

Imagina ahora que quieres ejecutar el mtodo kamehame siempre


y cuando sea una funcin ejecutable, simplemente cambiando la
posicin del operador ? lo tendrs resuelto:

goku.movements?.kamehame?()

Echa un vistazo a su traduccin en JavaScript:

var _ref;
if ((_ref = goku.movements) != null) {
if (typeof _ref.kamehame === "function") {
_ref.kamehame();
}
}

Uno de los alias que ms me sorprendi cuando aprend CoffeeS-


cript fue @ el cual se utiliza para sustituir el tpico this:

@twitter = "@soyjavi"
2. Sintaxis 25

Lo que estamos haciendo en este caso es establecer la variable del


contexto actual twitter con el valor "@soyjavi". En el prximo
artculo veremos como podemos conmutar de contextos de una ma-
nera sencilla, lo cual nos ser de gran ayuda en muchas ocasiones.
El ltimo alias que vas a ver ser :: que hace referencia a prototype,
entendiendo que con tu base actual de JavaScript sabes perfecta-
mente a que me refiero.

Goku::life = 10

Si no sabes muy bien de lo que te estoy hablando has incumplido el


pacto conmigo, debes estudiar JavaScript!. En el captulo 5, clases,
darmos un pequeo repaso al paradigma de los prototipos en
JavaScript con CoffeeScript.
3. Funciones, mbito y
Contexto
CoffeeScript elimina todo adorno barroco en la declaracin de
funciones tal y como ests acostumbrado en la programacin con
JavaScript. Lo sustituye por un smbolo simple y conciso como es ->
y como vers ms adelante debers dominarlo si quieres convertirte
en un verdadero CoffeeScripter.
Las funciones pueden declararse en una sola linea o en varias
lineas indentadas como por ejemplo se hace en otros lenguajes
como son Ruby o Python. Otra de las cosas maravillosas que te
vas a encontrar es que no hace falta definir el return de nuestra
funcin ya que existe una convencin donde la ltima expresin que
definamos dentro de una funcin automticamente se convertir en
el resultado de la misma. En otras palabras no es necesario utilizar
la sentencia return a menos que necesites que el flujo de tu funcin
necesite devolver algo antes.

3.1 Funciones

Como vale ms un ejemplo que mil palabras, con la siguiente linea


te descubro tu primera funcin en CoffeeScript:

hello = -> world

Como puedes ver he creado una funcin llamada hello la cual


devuelve automticamente la cadena de texto world, lo se, no es
una funcin pretenciosa pero si la compilas veras que el resultado
en JavaScript cambia bastante:
3. Funciones, mbito y Contexto 27

var hello = function() {


return world;
};

Como he comentado anteriormente a menos que sea estrictamente


necesario no es necesario declarar funciones en mltiples lineas.
Pero la funcin hello podra codificarse de la siguiente manera:

hello = ->
# ... amazing CoffeeScript code!
world

La compilacin en JavaScript seguir siendo exactamente igual que


en la primera funcin hello, por lo que en este punto tu decidirs
cuando y porqu utilizar funciones en una sola linea, recordando
siempre el respeto por el Clean Code.

3.2 Funciones y Argumentos

Como hemos visto la declaracin de funciones es sumamente


sencilla, pero el ejemplo anterior es poco verstil ya que nicamente
devuelve un valor constante. Veamos una funcin algo ms dinmi-
ca:

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

En esta ocasin tenemos una funcin divide que recibe dos argu-
mentos a y b los cuales se dividen entre si y se devuelve el resultado.
Esto mismo compilado en JavaScript:

http://www.amazon.com/Clean-Code-Handbook-Software-Craftsmanship/dp/
0132350882
3. Funciones, mbito y Contexto 28

var divide = function(a, b) {


return a / b;
};

Una de las cosas que ms cuesta en JavaScript es el control de


valores en argumentos de una funcin, pero gracias a CoffeeScript el
trabajo se simplifica considerablemente. Por ejemplo, imagina que
en nuestra funcin divide queremos que el argumento b por defecto
sea 1 si no introducimos ningn valor:

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

Como ves sigue siendo muy sencillo y curiosamente sigue siendo


una sola linea de cdigo, pero si analizamos la compilacin en
JavaScript:

var divide;

divide = function(a, b) {
if (b == null) {
b = 1;
}
return a / b;
};

Si estudiamos el cdigo vemos que controla si el argumento b es


null, en caso de que lo sea automticamente lo inicializa con el
valor 1. Si no te acabas de convencer de porqu CoffeeScript es una
de los mejores complementos para desarrollar Aplicaciones Webs,
te recomiendo que cierres este libro y te dediques a otra cosa.
Si estas leyendo esto es porque no te has negado a continuar
aprendiendo CoffeeScript, ahora vas a ver un nuevo ejemplo que
te har subir de nivel:
3. Funciones, mbito y Contexto 29

divide = (numbers...) ->


result = 0
numbers.forEach (number) -> result = result / number
result

Como ves en este ejemplo he introducido el smbolo ... (splats)


detrs del argumento numbers, haciendo que CoffeeScript espere un
numero indeterminado de argumentos y que los vaya dividiendo
y almacenando en la variable result. Veamos esto mismo en
JavaScript:

var divide,
__slice = [].slice;

divide = function() {
var numbers, result;
numbers = 1 <= arguments.length ? __slice.call(argume\
nts, 0) : [];
result = 0;
numbers.forEach(function(number) {
return result = result / number;
});
return result;
};

Un ejemplo que me gusta mucho ensear cuando doy charlas sobre


CoffeeScript, es demostrar la enorme flexibilidad que tiene para
controlar la entrada de argumentos en una funcin. Por ejemplo,
tenemos una funcin llamada race donde sabemos que va a haber
un winner pero no sabemos cuantos runners terminaran la carrera.
Necesitamos sacar por consola el winner y el resto de runners
separados por el caracter ,. Como hacerlo en una sola linea?:
3. Funciones, mbito y Contexto 30

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


ers.join(,)

Utilizar un splat en runners hace que CoffeeScript espere un


rango de valores y automticamente los convierta en un array de
elementos, siempre y cuando existan valores. Como vemos en el
ejemplo continuamos con la declaracin de funciones en una nica
linea pero si leemos el cdigo en JavaScript el numero de lineas crece
considerablemente:

var race,
__slice = [].slice;

race = function() {
var runners, winner;
winner = arguments[0], runners = 2 <= arguments.lengt\
h ? __slice.call(arguments, 1) : [];
return console.log(winner, runners.join(, ));
};

Los splats van mucho ms all, veamos como crear un sandwich


combinando argumentos:

sandwich = (top, ingredients..., base) -> # eat it?

Los argumentos que no son de tipo splat se asignarn en primer


lugar, por lo que si se llama a sandwich con dos nicos argumentos,
estos pasarn a top y base. Slo cuando hay tres o ms argumentos
se utilizar el argumento splat ingredients y con esto CoffeeScript
vuelve a reafirmarse con la convencin simplicidad frente a com-
plejidad.
Recordarte, como buen conocedor de los internals de JavaScript,
que tambin podramos no declarar ningn argumento y acceder a
ellos gracias al array arguments:
3. Funciones, mbito y Contexto 31

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

Aprovecho esta funcin para recordarte la interpolacin por medio


de #{} que aprendiste en el captulo anterior, acostmbrate a
utilizarla siempre que puedas. Veamos como quedara la funcin
avengers en JavaScript:

avengers = function() {
return "Hulk, Thor, Ironman, " + arguments[0] + "!";
};

3.3 Llamando a funciones

Hasta ahora has aprendido como declarar funciones con CoffeeS-


cript, sin argumentos, con argumentos y has conocido los splats
aunque todava no sabes como llamar a las funciones que hemos
escrito. CoffeeScript vuelve a conseguir de una forma muy simple
que nos centremos nicamente en el hecho y no en la forma:

result = divide 1, 2

Como ves no tenemos que utilizar parntesis ni punto y coma para


declarar el limite de los argumentos de una funcin, si compilamos
a JavaScript sera:

var result = divide(1, 2);

Podemos concatenar funciones de una manera sencilla, imagina


que no quieres guardar la suma en una variable result y que
nicamente te interesa lanzar un mensaje por tu pantalla gracias
al mtodo de JavaScript alert:
3. Funciones, mbito y Contexto 32

alert divide 1, 2

Fjate como CoffeeScript sabe perfectamente lo que quieres hacer y


compila un JavaScript lleno de complicadas ( y ):

alert(divide(1, 2));

Voy a complicarlo un poco ms, imagnate que tenemos una fun-


cin que recibe argumentos combinando valores String, Number,
Boolean con Objects. Veamos la f

hero = (year, properties, superpowers) ->

hero 1939, name: "Batman", city: "Gotham", false

Como ves llamo a la funcin sin delimitar la propia funcin ni


estableciendo las Curly Braces en el objeto properties, pero Cof-
feeScript y su magia vuelven a hacer acto de presencia para que la
funcin hero funcione sin problemas:

var hero;

hero = function(year, properties, superpowers) {};

hero(1939, {
name: "Batman",
city: "Gotham"
}, false);

Todava no hemos visto como llamar a una funcin sin argumentos,


y en esta ocasin se hace igual que en JavaScript utilizando nuestros
queridos (sarcasmo) e inseparables parntesis:
3. Funciones, mbito y Contexto 33

hello()

Tambin existe otra forma de llamar a funciones sin argumentos y


es utilizando el alias operador do, el cual utilizo siempre que puedo
ya que le da ms expresividad a mi cdigo:

do hello

Ambos ejemplos, como era de esperar, devuelven el mismo JavaS-


cript:

hello();

3.4 mbito

Por ahora no hemos controlado el ciclo de vida de nuestras varia-


bles, el mbito, por desgracia esta despreocupacin en JavaScript
nos puede llevar a futuros problemas dentro de nuestra aplicacin
web, menos mal que CoffeeScript nos ayudar en este proceso.
Vamos a ver un sencillo ejemplo:

lifes = 0
restartGame = -> lifes = 3
do restartGame

console.log "I have #{lifes} lifes in the game."


> I have 3 lifes in the game.

Como probablemente esperabas, la consola mostrar I have 3


lifes in the game., pero si realizamos un simple cambio,
conmutando las 2 primeras lineas:
3. Funciones, mbito y Contexto 34

restartGame = -> lifes = 3


lifes = 0
do restartGame

console.log "I have #{lifes} lifes in the game."


> I have 0 lifes in the game.

Ahora el resultado, sorprendentemente es totalmente diferente I


have 0 lifes in the game.. Curioso, tu funcin restartGame no
ha tenido ningn efecto sobre la variable lifes. Cmo ha podido
suceder esto? Te voy a mostrar otro ejemplo a ver si eres capaz de
comprender que est pasando:

restartGame = -> lifes = 3


do restartGame

console.log "I have #{lifes} lifes in the game."


> ReferenceError: lifes is not defined

Hemos conseguido generar un error de mbito de variable, y ahora


te pregunto como puedes saber el alcance de una determinada
variable? Muy fcil su mbito se define gracias a tres sencillas
reglas:

Cada funcin crea un mbito, y la nica manera de crear un


mbito es definiendo una funcin.
El ciclo de vida de una variable perdurar en el mbito ms
externo en el que se ha hecho una asignacin a esa variable.
Fuera de su mbito, una variable es invisible.

Tomando como ejemplo los anteriores ejemplos, el mbito de lifes


en el primer ejemplo fue el contexto global (GlobalScope), en el
segundo ejemplo, hubo una variable lifes en el mbito global
3. Funciones, mbito y Contexto 35

y otra en el mbito de la funcin restartGame, y en el ltimo


ejemplo, solo exista dentro de la funcin restartGame. Es por
eso que tenemos un ReferenceError sobre lifes tratando de ser
utilizada fuera de la funcin restartGame, puesto como habrs
podido descubrir la variable no existe.
En CoffeeScript al mbito se conoce como mbito lxico, y real-
mente es el mismo que en JavaScript, salvo que en este ltimo la
declaracin del mbito va asociada a la palabra reservada var y en
CoffeeScript el mbito se define con la primera asignacin. Esto
te ahorra tiempo a la hora de desarrollar tu cdigo, pero siempre
siendo responsable y teniendo cuidado ya que puedes provocar
inconscientemente el llamado shadowing de variables que no es otra
cosa que crear variables fuera de su rea de uso.
En CoffeeScript solo existen dos maneras de realizar shadowing
a una variable: la primera la hemos visto en el segundo ejemplo
de restartGame, creando una variable junto con otra variable de
mbito ms interno. La otra manera es como argumento de una
funcin:

lifes = 3
insertCoin = (coins, lifes) -> lifes += coins * 3
console.log insertCoin 3, lifes
> 12

console.log lifes
> 3

Bien vamos a analizar que est pasando con la funcin insertCoin,


posiblemente pensabas que por cada coin introducida tu vida se iba
a multiplicar por 3 el numero de lifes de tu variable ms externa.
Pero has visto que al consultar lifes ves que sigue siendo 3 y no
12 como esperabas. Realmente la respuesta es sencilla, la funcin
insertCoin genera un nuevo mbito para lifes puesto que se pasa
3. Funciones, mbito y Contexto 36

como parmetro y el cometido de esta operacin es nicamente


devolver el resultado de la operacin, el cual no se asigna a lifes.
El shadowing normalmente esta considerado un mala praxis en
programacin JavaScript y por lo tanto debes intentar evitarlo.
Intenta dar nombres diferentes a tus variables, para no llegar a
confusiones sobre el mbito de las mismas.
En este punto te preguntars, Cmo puedo asignar a una variable
el mbito correcto sin realizar una asignacin? La respuesta es que
en CoffeeScript es imposible. En lugar de eso tendrs que realizar
una asignacin tradicional como por ejemplo usando un null o
cualquier otro valor inicial no sensible. He aqu un ejemplo:

hero = null

window.onload = -> hero = "Batman"

3.5 Contexto

mbito y contexto estn muy relacionados dentro de CoffeeScript,


pero no por ello deben mezclarse los conceptos. Mientras que el
mbito se preocupa de la variable y el identificador al que hace
referencia, el contexto se preocupa de la palabra reservada this,
y en el caso de CoffeeScript de su alias @.
Los recin llegados al mundo de JavaScript y CoffeeScript a menudo
se encuentran con un desconcertante y poco descriptivo this. Uti-
lizndolo correctamente, te sientes verdaderamente un verdadero
SuperHeroe dispuesto a salvar al mundo. Usndolo errneamente,
puede ser sin lugar a duda un enorme foco de errores. Parte de la
confusin deriva en la palabra misma, la gente espera que this hace
referencia a este objeto. En su lugar, debes pensar en ello como
este contexto y como vers ms adelante, el contexto, this/@,
puede ser totalmente diferente cada vez que se llame a una funcin.
Para los ejemplos utilizaremos un simple mtodo createPower:
3. Funciones, mbito y Contexto 37

createPower = (power) -> @power = power

En este caso @power y power son variables totalmente diferentes,


power, que podras haberla llamado como quisieses, es una variable
local y nunca se ver fuera de la funcin createPower, mientras que
@power es una propiedad del contexto.
El objetivo principal de contexto es dar a los mtodos de un objeto
(en funciones aadidas como propiedades) una forma de referirse
al objeto que est siendo llamado. Veamos otro ejemplo:

hero = {}
hero.createPower = createPower
hero.createPower "Fly"

console.log hero.power
> "Fly"

Cuando llamamos a hero.createPower, realmente estamos llaman-


do al mtodo createPower que habamos creado antes con el objeto
hero como contexto; por lo que @ en la funcin se refiere al objeto
hero, por lo que crear un atributo @name haciendo referencia a
hero.name. La funcin en si no ha cambiado, y podramos llamarla
las veces que necesitemos no cambiando por ello el objeto Hero:

createPower "Fury"

console.log hero.power
> "Fly"

Otro ejemplo que podemos realizar es no aadir la funcin a ningn


objeto en particular y utilizar los mtodos call o apply propios de
la funcin (y qu como sabes todas las funciones JavaScript tienen).
El mtodo apply necesita un contexto y un array de argumentos
para ejecutarse:
3. Funciones, mbito y Contexto 38

superman = {}
createPower superman, ["Fly"]

console.log superman.power
> "Fly"

El mtodo call funciona exactamente igual, excepto por que recibe


un solo argumento y no un array. De esta manera apply es mucho
ms verstil puesto que puede recibir una lista de argumentos, de
todas formas veamos el equivalente call al ejemplo anterior:

createPower.call superman, "Fly"

Por ultimo veremos otra manera de dar a una funcin un contexto


y es utilizando la palabra reservada new, el cual creara un nuevo
objeto utilizando la funcin como constructor:

Power = createPower
heroes[1] = new Power "Fly"
heroes[2] = new Power "Fury"
console.log heroes[1].power
> Fly
console.log heroes[2].power
> "Fury"

Como te estars dando cuenta la palabra new no est devolviendo


el resultado de la funcin createPower, en cambio crea un nuevo
objeto, ejecuta la funcin en el contexto del objeto y tras ello
devuelve el objeto en si. Ahora ya has alcanzado un nuevo nivel
como desarrollador CoffeeScript, vale la pena que repasemos juntos
lo aprendido:

Cuando utilizas la palabra new delante de una llamada a una


funcin, el contexto es el nuevo objeto.
3. Funciones, mbito y Contexto 39

Cuando ejecutas una funcin mediante call o apply, el


contexto es el primer argumento.
Si una funcin se llama como una propiedad de objeto
obj.func o obj['func'], se ejecuta en el contexto de ese
objeto.
Si no es ninguna de las reglas anteriores, la funcin se ejecuta
en el contexto global.

3.6 Cambio de contexto en funciones

Los cambios de contexto son algo comn en JavaScript, especial-


mente en los callbacks de eventos, por lo qu CoffeeScript nos
brinda la posibilidad de manejar esta situacin muy facilmente.
Lo ms comn dentro de una funcin es la variacin de -> por la
llamada Flecha Ancha o RocketArrow =>.
Usando => en vez de la Flecha Fina -> te aseguras que el contexto
de la funcin ser el local. Por ejemplo:

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

La razn por la que debes utilizar =>, dejando que CoffeeScript


haga todo el trabajo por nosotros, es para que el callback de
addEventListener no se ejecute en el contexto de el y se ejecute
en el contexto local donde esta declarada la sentencia.
Como hace mucho que no ves cdigo JavaScript, te voy a ensear
la compilacin de este ejemplo para que veas que es lo que hace
CoffeeScript:
3. Funciones, mbito y Contexto 40

var _this = this;

el.addEventListener("click", function(event) {
return _this.handler(event);
});

Como ves el truco est en crear una variable _this que hace referen-
cia al @ global, y por lo tanto es accesible desde addEventListener.
En cambio si utilizamos -> el contexto es el de el y no podramos
acceder a la funcin handler:

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


el.trigger "click"

> ReferenceError: handler is not defined

Comprueba que en JavaScript ya no existe la variable this:

el.addEventListener("click", function(event) {
return this.handler(event);
});
el.trigger("click");

En este punto terminamos este captulo, en mi opinin junto con


las Clases (que veremos en un captulo futuro) el tratamiento de
Funciones es el area ms importante de CoffeeScript. Espero que
haya sido de tu agrado y que ahora te sientas capaz de dominar las
funciones en CoffeeScript como nunca lo habas imaginado.
4. Objetos y Arrays
Ya dominas las funciones con CoffeeScript, ahora toca descubrir
como utilizar tus funciones con colecciones de datos: los objetos y
Arrays.
Comenzaremos echando un vistazo a los objetos como una buena
propuesta para almacenar datos. Tras esto aprenders como utilizar
las listas, las cuales te darn un buen mecanismo para ordenar nues-
tros datos. Desde aqu comenzaremos con las estructuras iterativas
loop, las comprensiones y la creacin directa de arrays gracias a
ellas. Seleccin de matrices en base a matching y mucho mas.

4.1 Recordando JavaScript y sus Objetos

Antes de comenzar con la sintaxis CoffeeScript, ser mejor que


demos un breve repaso a los objetos en JavaScript, reconociendo
que casi todo es un objeto; las nicas excepciones son las primitivas:
boolean, number y string y las constantes undefined y NaN. El
objeto ms simple se escribira:

var object = new Object();

Aunque comnmente se suele utilizar la sintaxis heredada de JSON:

var object = {};

Existen muchsimas otras formas de creacin de objetos, es ms


en el captulo anterior hemos estado utilizando algunas de ellas,
http://json.org
4. Objetos y Arrays 42

puesto que todas las funciones son en si objetos (puesto que no son
ni boolean, number, string, undefined o NaN ).
Para acceder a las propiedades de un objeto tenemos dos formas, con
la notacin simple . o con la notacin tipo bracket {}. La primera es
sumamente sencilla de utilizar: obj.x hace referencia a la propiedad
x del objeto obj. La notacin via bracket es mucho ms verstil,
puesto que cualquier expresin que se incluya entre los brackets
se evaluar y converir a un string utilizndose como nombre de
propiedad, veamos el mismo ejemplo obj['x']
Normalmente, utilizars la notacin por punto si conoces el nombre
de la propiedad previamente y en el caso de que lo tengas que
determinar dinmicamente utilizars la notacin por bracket. Pero
no siempre el primer caso funciona:

symbols.* = 'plus' # Falla!!


symbols.['*'] = 'plus'

La primera sentencia falla ya que + esta reservado como operados,


mientras que la segunda sentencia al ser pasada como string no tie-
ne ese problema. Creo que por ahora no hace falta que recordemos
ms particularidades de JavaScript.

4.2 Objetos

Los objetos en CoffeeScript se pueden crear exactamente igual que


en JavaScript, con nuestras queridas Curly Braces y una lista de
declaraciones de Clave/Valor:

numbers = {one: 1, two: 2}

Sin embargo, al igual que en la invocacin de funciones, CoffeeS-


cript nos permite aligerar nuestro cdigo dejndonos a nuestra
4. Objetos y Arrays 43

eleccin la utilizacin de los caracteres {}. Personalmente, las quito


siempre y adems utilizo el nivel de indentacin con las nuevas
lineas como sustituto del separador , de propiedades:

numbers =
one: 1
two: 2

Con la exclusin completa de {} y , conseguimos que nuestro objeto


sea ms parecido a un YAML:

kids =
brother:
name: "Max"
age: 11
sister:
name: "Ida"
age: 9

Este ejemplo seguro que te har sonrer ademas de ver el verdadero


potencial de la creacin de objetos en una linea:

fellowship = wizard: 'Gandalf', hobbits: ['Frodo', 'Pip\


pin', 'Sam']

La magia de CoffeeScript se encuentra en que cada vez que encuen-


tra el caracter : sabe que ests haciendo referencia a un objeto.
Esta tcnica es especialmente til cuando una funcin tiene un
argumento que es un objeto:

http://yaml.org/
4. Objetos y Arrays 44

findPeople latitude, longitude, order: true

Compilando a JavaScript de la siguiente manera:

drawSprite(latitude, longitude, {order: true});

Aunque ya tienes una base de JavaScript, vale recordar el uso de


this en esta ocasin vamos a crear un objeto que tenga una funcin
toString que devuelva serializado alguna de las propiedades de
nuestro objeto. Veamos como:

podcast =
number : 11
title : 'Porqu es difcil testear?'
description: 'Conversacin con Javier Acero sobre tes\
tear y programar.'
details:
homepage : 'http://www.bastayadepicar.com'
url : 'http://www.bastayadepicar.com/episodio/\
011'
toString: -> "#{@number}. #{@title}"

Como ves existe el caracter @ que realmente hace referencia a this


que como ya sabemos esta marcando que el contexto es el suyo mis-
mo (dado que es una flecha fina ->). @ no deja de ser un facilitador
ms de CoffeeScript. Una de las cosas que siempre recomiendo a la
hora de trabajar con CoffeeScript es ver el cdigo compilado para
analizar las estructuras JavaScript que genera, analicemos pues:
4. Objetos y Arrays 45

var podcast;
podcast = {
number: 11,
title: 'Porqu es difcil testear?',
description: 'Conversacin con Javier Acero sobre tes\
tear y programar.',
details: {
homepage: 'http://www.bastayadepicar.com',
url: 'http://www.bastayadepicar.com/episodio/011'
},
toString: function() {
return "" + this.number + ". " + this.title;
}
};

En JavaScript, no puedes usar palabras reservadas como atributos


de un objeto, por ejemplo class. CoffeeScript si te permite hacerlo
puesto que todos los accesos a las propiedades los realizar por
notacin bracket. Veamos el ejemplo module.class = 'atom' el
cual compilado a JavaScript ser module['class'] = 'atom';.
Un ltimo apunte sobre objetos en CoffeeScript, recomiendo enca-
recidamente el uso de la expresin of para conocer si una propiedad
existe dentro de un determinado objeto:

console.log wizard of fellowship

4.3 Arrays

Los arrays siguen requiriendo los caracteres [] para indicar sus


elementos, por lo que tampoco vas a encontrar mucha diferencia
con JavaScript. De todas formas puedes utilizar la indentacin como
delimitador de elementos y podrs finalizar con , algo que en
JavaScript no est permitido y suele dar bastantes quebraderos de
cabeza. Veamos unos ejemplos:
4. Objetos y Arrays 46

numbers = [1, 2, 3]
letters = [
'A'
'B'
'C'
]
axys = [x, y, z,]

Posiblemente pensars que no puedo hablar mucho ms de Arrays,


nada ms lejos de la realidad a partir de ahora voy a poner
casos de uso en combinacin con funcionalidades de JavaScript y
CoffeeScript.

Obtener el valor mximo de un array

Imagina que tienes un array numrico y te gustara obtener el valor


mximo, seguramente ahora estars pensando en una iteraccin en
JavaScript, una variable que va quedndose con el mayor numero
y al final de la iteraccin (evidentemente) tendrs el mayor. Bien
vamos a hacerlo al estilo CoffeeScript:

Math.max [12, 32, 11, 67, 1, 3]...

Math.max compara todos los argumentos y devuelve el mayor de


ellos. Para convertir un array a argumentos fjate que utilizo la
elipsis ..., una tcnica muy utilizada para pasar un gran numero
de argumentos a una funcin.

Mapeando Arrays

Imagina, tienes un array de objetos y quieres crear otro array to-


mando ese como base. Lo mismo que el caso anterior, posiblemente
te pondrs a hacer iteraciones, acumuladores Vamos a ver que
puede hacer CoffeeScript por nosotros:
4. Objetos y Arrays 47

movies = [
name: "Batman", year: 1991, hero: true
,
name: "Spiderman", year: 2003, hero: true
,
name: "Superman", year: 1984, hero: true
,
name: "KickAss", year: 2011, hero: false
]
heroes = movies.map (movie) -> movie.name if movie.hero\
is true

Como ves he utilizado la conocida funcin map que nos permite


hacer operaciones con los elementos de un array. Como puedes
leer, porque una cosa que nos da CoffeeScript es la comprensin sin
conocimiento, en el nuevo array heroes solo existirn los strings
'Superman', 'Batman' y 'Spiderman' ya que estamos filtrando
por la propiedad hero. Como has podido comprobar tambien he
eliminado las Curly Braces, y he marcado la dimensin de cada
objeto, con un nivel de indentacin (fijate que la , esta en un nivel
inferior).
Los mapeos son una buena herramienta para manejar transforma-
ciones ms complicadas que la que hemos realizado, ms adelante
conocers otra manera de hacerlo por medio de comprensiones.

Reduciendo Arrays

Imagina, tenemos un array de elementos y nos gustara hacer algn


tipo de operacin por todos los elementos
4. Objetos y Arrays 48

[1,2,3,4].reduce (x, y) -> x + y


> 10
["batman", "superman", "spiderman", "hulk"].reduceRight\
(x, y) -> x + ", " + y
> 'batman, superman, spiderman, hulk'

Tambin podramos hacer algo ms complejo como generar objetos


tomando como referencia una lista de objetos:

heroes =
{ name: 'batman', year: 1988 }
{ name: 'superman', year: 1981 }
{ name: 'spiderman', year: 2012 }

heroes.reduce (x, y) ->


x[y.name]= y.year
x
, {}
> { batman: 1988, spiderman: 1981, spiderman: 2012 }

Los mtodos reduce y reduceRight se introdujeron en la versin 1.8


de JavaScript, en este caso CoffeeScript nos provee de una manera
natural y simple para utilizarlos.

Rangos de Arrays

Imagina, que tienes que crear un array que contenga una serie nu-
mrica. Deja de hacer ms iteraciones y conoce un nuevo operador
en CoffeeScript:
4. Objetos y Arrays 49

numbers = [1..10]
> [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ]
numbers = [10..1]
> [ 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 ]

Cuando escribimos el operador .. CoffeeScript interpreta que ne-


cesitamos una serie numrica entre el primer (1) y el ultimo valor
(10). Si queremos omitir el ultimo valor dentro de la serie tendremos
que utilizar el operador ... como vemos en el siguiente cdigo:

numbers = [1...10]
> [ 1, 2, 3, 4, 5, 6, 7, 8, 9 ]

Filtrando Arrays

Imagina, necesitas filtrar un array por una determinada condicin


booleana.

numbers = [1..10]
numbers.filter (number) -> number > 5

En el mtodo filter vemos que define como parmetro una fun-


cin en la cual estamos pidiendo que se quede con los nme-
ros del array mayores que 5 por lo que tendremos el resultado
[6,7,8,9,10].

Uniendo Arrays

Imagina, necesitas unir dos arrays en una sola y no quieres crear un


iterador, mira que sencillo:
4. Objetos y Arrays 50

numbers_1 = [1, 2, 3]
numbers_2 = [4, 5, 6]
numbers = numbers_1.concat numbers_2
> [1, 2, 3, 4, 5, 6]

Realmente concates una funcin de JavaScript, pero mucha gente


no la utiliza y es realmente util. La gran diferencia con el mtodo
push es que concat crea un nuevo array y deja los arrays que se
tomaron como base sin modificarse.

4.4 Comprensiones
Como hemos visto anteriormente podemos hacer mapeos de fun-
ciones de una manera muy sencilla, pero CoffeeScript nos da las
comprensiones un tipo de operacin que los desarrolladores de
Python podrn reconocerlas fcilmente. Vamos a volver a realizar
un mapeo mediante comprensin de nuestra conocida array heroes:

movies = [
name: "Batman", year: 1991, hero: true
,
name: "Spiderman", year: 2003, hero: true
,
name: "Superman", year: 1984, hero: true
,
name: "KickAss", year: 2011, hero: false
]
heroes = (movie.name for movie in movies when movie.her\
o)
> [ 'Doctor Teeth', 'Janice', 'Sgt. Floyd Pepper', 'Zoo\
t', 'Lips', 'Animal' ]

Como puedes comprobar es ms sencillo que utilizar el mtodo map


y sobre todo la creacin del array heroes es realmente comprensible
(lelo y dime que no).
4. Objetos y Arrays 51

Si todava no te he convencido vamos a ver otro ejemplo de dos


maneras, la aburrida y la divertida (jedy-mode). Teniendo un array
heroes:

heroes = ['Batman', 'Spiderman', 'Superman']

Muestro por pantalla unos heroes determinados, pero para ello


escribo 3 lineas de cdigo:

for hero, index in heroes


if index % 2 == 0
console.log(hero)

Ahora vas a hacerlo como un verdadero Jedi, sintiendo la fuerza y


elegancia que ofrece CoffeeScript:

console.log hero for hero, index in heroes when index %\


2 is 0

Como vemos, dentro del for podemos adems de tener cada ele-
mento en hero, podemos saber el indice del mismo como segundo
argumento (en este caso index). Con lo que utilizamos este segundo
argumento para hacer la funcin de filtrado. Ahora ya puedes ir a tu
consola de CoffeeScript para jugar con tus heroes y comprensiones.
Si todava no estas impresionado por esta capacidad que tiene este
lenguaje, solo me queda sorprendente con una implementacin del
mtico FizzBuzz en una nica linea:

fizzbuzz = (['fizz' unless i%3] + ['buzz' unless i%5] o\


r i for i in [1..100])

Esta implementacin no es ma, proviene del blog de Ricardo


Tomasi, el cual recomiendo que le eches un vistazo.
http://ricardo.cc/
5. Clases
Si lo s, hablar de clases en JavaScript puede ser algo peligroso dado
que algunos puristas, aquellos que vienen de lenguajes tradicionales
y tipados, no toman en serio al lenguaje padre de CoffeeScript. Tal
vez sea porque JavaScript sea el lenguaje ms famoso que utiliza el
paradigma basado en prototipos, y los dems como Cecil, Omega,
MOO no sean tan conocidos. Sin embargo, las clases son tan utiles
en JavaScript como lo son en otros lenguajes, con CoffeeScript lo
que conseguimos es tener un nivel de abstraccin mucho mayor.
Desde este captulo daremos un pequeo repaso a los prototipos y
nos meteremos de lleno en la creacin de nuestras primeras clases
con CoffeeScript, utilizando herencia, poliformismo

5.1 Prototipos

Antes de comenzar con las clases es necesario recordar como


funciona un lenguaje prototpico como JavaScript, un prototipo
es un objeto del cual otros objetos heredan sus propiedades. Por
ejemplo vamos a crear nuestro objeto Hero el cual tendr un mtodo
prototpico says, veamos como:

Hero = (@power) ->


Hero::says = -> console.log "My superpower it's #{@powe\
r}!"

Comenzamos declarando Hero, recuerda que existe una convencin


para que las bases tengan la primera letra en mayscula, el cual
recibe el argumento power en su constructor, con esto conseguimos
que este variable est disponible en la instancia que creemos de
Hero. Veamos como queda en JavaScript:
5. Clases 53

var Hero;

Hero = function(power) {
this.power = power;
};

Hero.prototype.says = function() {
return console.log("My superpower it's " + this.power\
+ "!");
};

Simplemente por recordar; un constructor es una funcin, y en


javascript, toda funcin es un objeto y como cualquier objeto tiene
propiedades y mtodos. Una funcin, por defecto, tiene una serie
de propiedades, como: length, constructor, prototype y algunos
mtodos como: call, apply, entre otros. Cualquier funcin es
susceptible de convertirse en un constructor, basta con anteponer
el operador new a la llamada de la funcin.
Ahora vamos a crear un par de superheroes, perdn, un par de
instancias Hero estableciendo a cada una de ellas su superpoder y
llamando al mtodo says:

superman = new Hero "fly"


superman.says()
> 'My superpower it's fly!'

batman = new Hero "a belt with gadgets"


batman.says()
> 'My superpower it's a belt with gadgets!'

Como podas prever cada instancia de Hero dice que tiene un poder
distinto porque el mtodo says hace referencia al atributo power de
cada instancia. Evidentemente podemos acceder al atributo power:
5. Clases 54

superman.power
> 'fly'

Cuando usas new, ocurren varias cosas:

Se crea un nuevo objeto


El nuevo objeto recibe el prototipo desde el constructor
Se ejecuta el constructor con el contexto del nuevo objeto

Veamos un ejemplo diferente, mezclando prototipos con estticos:

Hero = (@power) ->


Hero.count++
@number = Hero.count
@says()

Hero.count = 0
Hero::says = -> console.log "#{@number}. My superpower \
it's #{@power}!"

En este caso ampliamos el constructor de Hero, haciendo que tenga


un contador de instancias contenido en la propiedad count la cual
se incrementar cada vez que se crea una nueva instancia (de
ah que la sentencia no fallar, si posteriormente declaramos esa
variable). Adems creamos un atributo de instancia @number que
nos devolver el valor interno de Hero.count, la ltima sentencia
del constructor ser llamar automticamente al mtodo prototpico
says demostrando que todo lo creado funciona. El resultado sera:
5. Clases 55

superman = new Hero "fly"


> '1. My superpower it's fly!'

batman = new Hero "a belt with gadgets"


> '2. My superpower it's a belt with gadgets!'

Resumiendo, cada vez que se ejecuta el constructor de Hero, los


pasos son:

Se asigna el superpoder a la instancia con el shortcut @ dede


el argument
Se incrementa el contador de instancias count
Copia el valor a la propiedad @number
Ejecuta la funcin heredada @says

Recuerda que todas las funciones del nuevo objeto se ejecutarn en


el contexto del propio objeto, aunque en el captulo destinado a fun-
ciones ya aprendiste como cambiar los contextos de las funciones
no?.

5.2 Clases
Ahora que ya hemos recordado los prototipos puedo decirte que
las clases en CoffeeScript se basan en ellos. Hay varias bibliotecas
que han intentado acercar el mundo de las clases a JavaScript, pero
desde mi humilde punto de vista no les ha ido muy bien ya que
la sintaxis ha quedado demasiado complicada. Es entonces cuando
llega CoffeeScript al rescate y logra simplificar la creacin de una
clase. Ahora vamos a crear nuestra primera clase Hero:

class Hero

Como ves la simpleza es mxima y sobre todo entendible y com-


parable con otros lenguajes de programacin. Vamos a ver como
quedara en JavaScript:
5. Clases 56

var Hero;
Hero = (function() {
function Hero() {}
return Hero;
})();

Como vemos, nicamente hemos declarado una nueva clase Hero,


y la diferencia entre la carga de sintaxis entre CoffeeScript y
JavaScript es abismal; espero que ahora me entiendas. CoffeeScript
nos proporciona con eficacia una abstraccin de la base prototpica,
permitindonos escribir cdigo mucho ms conciso, y sin perder
ninguno de los beneficios de los objetos en JavaScript. Ahora
creemos un constructor como en el anterior apartado dedicado a
los prototipos:

class Hero
constructor: (@power) ->

superman = new Hero "fly"


superman.power
> 'fly'

Compilndose a JavaScript, y viendo claramente lo mucho que


ganas con CoffeeScript:

var Hero;
Hero = (function() {
function Hero(power) {
this.power = power;
}
return Hero;
})();

var superman = new Hero("fly");


5. Clases 57

superman.power;
> 'fly'

Ahora vas a aprender la diferencia en la declaracin entre mtodos


estticos y mtodos de instancia o prototpicos, para que puedas
hacer comparaciones vamos a continuar con nuestro ejemplo de
Hero:

class Hero
# static private
_count = 0

constructor: (@power) ->


_count++
@says()

# Instance methods
says: ->
console.log "#{@number()}. My superpower it's #{@po\
wer}!"

number: -> _count

Como vemos lo primero que hago es crear una variable privada


_count que sea accesible para todo el contexto de la clase Hero.
En el constructor, incremento el contador y llamo a la funcin
de instancia says. Por qu CoffeeScript sabe que el mtodo de
instancia? muy sencillo porque estamos estableciendo el alias @
indicando que el contexto de trabajo es el del constructor, ergo el
de una instancia.
Para declarar mtodos de instancia debes utilizar el operador : junto
con el nombre del mtodo que deseas crear. En nuestra clase hemos
creado 2 mtodos: says que muestra por pantalla el numero de
5. Clases 58

instancia y el poder de nuestro hero y number que muestra el valor


de la variable _count.
Ahora imagina que necesitas un mtodo esttico para la clase Hero,
por ejemplo vamos a crear un mtodo count que nos de el numero
de instancias creadas hasta el momento:

class Hero
# ... previous code ... #

# static public method


@count: ->
console.log "Number of instances #{_count}"

De esta manera ahora segn vas creando instancias, podrs llamar


al mtodo count de la clase Hero, el cual solo es accesible desde la
clase y no desde sus instancias:

superman = new Hero "fly"


batman = new Hero "a belt with gadgets"

Hero.count()
> 'Number of instances 2'

5.3 Herencia

La implementacin de clases de CoffeeScript no estara completa


sino hubiese ningn mecanismo de obtener herencia entre clases,
tranquilo CoffeeScript la tiene. Vas a poder heredar de otra clase
simplemente usando el operador extends. En el siguiente ejemplo
vas a ver como crear una clase base Vehicle, de la que extenderemos
los vehculos de nuestros heroes. Suena divertido no? comencemos:
5. Clases 59

class Vehicle
fuel: 100

constructor: (@type, @hero) ->

use: ->
@fuel--
if @fuel > 0
console.log "#{@hero} is using a #{@type}"
else
console.log "Upps!! No fuel in the tank of #{@con\
structor.name}"

Bien, lo primero que he hecho ha sido crear una variable de instan-


cia fuel, recuerda :, que contendr el nivel de gasolina del deposito.
El constructor de nuestra clase Vehicle recibe dos argumentos, type
para indicar el tipo de vehculo y heropara indicar el nombre del
heroe dentro del vehculo. Por ltimo he declarado un mtodo de
instancia use el cual ir restando gasolina y testar el nivel de la
misma para dar un mensaje por consola.
Ahora vamos a crear nuestra primera clase extendida de Vehicle,
as que vamos a coger a Batman y le vamos a meter dentro de su
BatMobile:

class BatMobile extends Vehicle


constructor: ->
super "car", "Batman"

Como puedes comprobar lo nico que hago a la hora de crear la


clase BatMobile es usar el operador extends haciendo referencia
a Vehicle. Tras esto en el constructor de la nueva clase llamo al
constructor de Vehicle con el mtodo super y los 2 argumentos que
necesita "car" haciendo referencia a @type y "Batman" haciendo
referencia a @hero. Tan sencillo como eso, ahora podemos hacer
que Batman use su vehculo:
5. Clases 60

batmobile = new BatMobile()


batmobile.use()
> 'Batman is using a car'

Ahora voy a crear otro vehculo y voy a sobreescribir la variable


fuel en la nueva clase y as podr ver el diferente comportamiento
del mtodo use:

class BatPod extends Vehicle


fuel: 0

constructor: ->
super "moto", "Robin"

Pobre "Robin" cuando vaya a utilizar la nueva clase BatPod no va


a poder usarla:

batpod = new BatPod()


batpod.use()
> 'Upps!! No fuel in the tank of BatPod'

Como ves en el mtodo use de la clase Vehicle utilizo el atributo


@constructor.name que hace referencia al nombre de la clase, en
este caso BatPod. Como queremos que Robin pueda disfrutar de
su vehculo vamos a crear un mtodo de instancia y exclusivo de
BatPod para que recargue la gasolina:

class BatPod extends Vehicle


# ... previous code ... #

refuel: ->
@fuel = 10
5. Clases 61

Finalizando este apartado tengo que decir que las propiedades


estticas se copian en las subclases, en lugar de estar heredadas por
referencia. Esto es debido a la arquitectura e implementacin de los
prototipos de JavaScript, y desgraciadamente es un problema difcil
de solucionar.

5.4 Polimorfismo

Uno de los usos interesantes de las clases es el llamado polimorfismo,


un concepto de la programacin orientada a objetos el cual podra
decirse que en esencia refiere al comportamiento de los objetos, no
a su pertenencia a una jerarqua de clases (o a sus tipos de datos).
Te voy a refrescar este concepto con un ejemplo muy sencillo:

class Vehicle
constructor: (@fuel = 10) ->
burnout: ->
throw new Error "I'm a abstract method"

En este caso nuestra clase Vehicle tiene un mtodo abstracto


burnout el cual si intentamos llamarlo desde una nueva instancia
de esta clase nos dar una excepcin. Este mtodo se utilizar en las
subclases de Vehicle y nos devolver el numero de kilmetros que
puede recorrer el vehculo al ejecutar el mtodo:
5. Clases 62

class BatMobile extends Vehicle


constructor: ->
super fuel = 50
burnout: ->
console.log @fuel / 25

class BatPod extends Vehicle


burnout: ->
console.log @fuel / 8

La diferencia entre el BatMobile y el BatPod es nicamente que el


primero establece el argumento fuel con una cantidad de 50. Como
puedes ver cada mtodo burnout realiza diferentes operaciones
puesto que el consumo de los vehculos es distinto.

kmInBurnout = (vehicle) ->


unless vehicle instanceof Vehicle
throw new Error "vehicle requires a Vehicle instance\
!"
console.log vehicle.burnout()

kmInBurnout new BatMobile()


> 2

kmInBurnout new BatPod()


> 1,25

La funcin kmInBurnout lo primero que hace al recibir un argumen-


to es comprobar que sea una instancia de la clase Vehicle, para
ello se utiliza la expresin instanceof. En el caso de que sea una
instancia vlida devolver por consola el resultado de la funcin
burnout.
6. Modularizacin
Uno de los grandes problemas que existe con JavaScript, ergo con
CoffeeScript, es que no importa el numero de ficheros que tengas
tu proyecto. JavaScript solo sabe de lineas y por lo tanto existe la
posibilidad de que El Libre Albedro haga acto de presencia, creando
estructuras incorrectas, inmantenibles y peligrando el GlobalScope.
Se que esto puede darse en todos los lenguajes de programacin,
pero bajo mi punto de vista JavaScript Todos estos problemas crecen
exponencialmente cuando es un equipo el que se enfrenta a un pro-
yecto en JavaScript/CoffeeScript, tenemos/tienes que solucionarlo.
En este captulo he intentado reunir algunos puntos interesantes
que tienes que tener en cuenta para tener un cdigo organizado y
mantenible; independientemente del patrn de diseo que utilices.

6.1 Namespacing
Como ya vimos en captulos anteriores, todas las variables que se
declaran en una funcin solo existen en el mbito propio de la
funcin. Cada nuevo fichero que compila CoffeeScript a su vez
genera una funcin autoejecutable, con su propio mbito, y por
lo tanto si tenemos dos ficheros las variables de un fichero no
sern visibles desde el otro, a menos que estn declaradas en el
GlobalScope. Por una parte esta bien pensado ya que a menos que lo
queramos hacer consecuentemente, tu GlobalScope quedar limpio
y sin saber de tus mil y una funciones.
Bien, y ahora te pregunto cmo podemos acceder a esas funciones
y variables que tenemos en mdulos separados y fuera del GlobalS-
cope?; muy sencillo. Debemos declarar una nica variable global, en
browsers asignarla al objeto window y en proyectos NodeJS al objeto
global. Veamos como:
6. Modularizacin 64

(global or window).libjs = {}

Tan sencillo como lo que ves, nos aseguramos que nuestro objeto
libjs va a declararse en entornos browser o NodeJS. A partir de
ahora ya podemos crear nuestros diferentes mdulos utilizando el
namespace libjs:
math.coffee

libjs.math =
sum : (a, b) -> a + b
rest: (a, b) -> a - b
# ... #

constants.coffee

libjs.CONST =
MIN_VALUE: 10
MAX_VALUE: 90

class.coffee

class libjs.Hero

Este es un primer acercamiento a como tener organizados tus


fuentes creando un sistema de Namespaces, de todas formas, te
recomiendo que junto al Namespacing debers utilizar algn patrn
de diseo; siempre adecuado a la naturaleza de tu proyecto.

6.2 Mixins

Los llamados mixins no estn soportados de forma nativa en


CoffeeScript, por la sencilla razn de que son triviales y cada
http://en.wikipedia.org/wiki/Mixin
6. Modularizacin 65

desarrollador hace su propia implementacin; algo parecido a lo


que pasa con el patrn MVC (sarcasmo). En el siguiente ejemplo
podemos ver un ejemplo:

extend = (obj, mixin) ->


obj[name] = method for name, method of mixin obj

include = (class_reference, mixin) ->


extend class_reference.prototype, mixin

include Hero, film: true


(new Hero).film

En este ejemplo declaro extend e include, mientras que el primero


se encarga de sobrecargar propiedades estticas el segundo se ocupa
de propiedades de instancia. En el ejemplo puedes comprobar
como creo una propiedad de instancia film para indicar si nuestro
superheroe ha tenido una pelcula, por defecto true.
Los mixins son un buen patrn para compartir lgica de negocio
comn entre diferentes mdulos de tu aplicacin. La ventaja de los
mixins es que puedes incluirlo en ms de un objeto o clase, mientras
que comparndolo con la herencia de una clase solo puede heredar
de un nico origen.

6.3 Extendiendo clases

Una cosa que aprend cuando lei mi primer libro sobre CoffeeScript,
escrito por Alex MacCaw, fue que los mixins no son suficientes
ya que no estan muy orientados a objetos. Necesitamos una mejor
manera de integrar mixins en nuestras clases CoffeeScript, y Alex
pens en crear una clase base Module de la que el resto de clases
extendiensen. La transcribo tal cual el lo pens:
http://alexmaccaw.com/
6. Modularizacin 66

KEYWORDS = ['extended', 'included']

class Module
@extend: (obj) ->
for key, value of obj when key not in KEYWORDS
@[key] = value
obj.extended?.apply(@)
@

@include: (obj) ->


for key, value of obj when key not in KEYWORDS
@::[key] = value
obj.included?.apply(@)
@

Como vemos crea dos funciones estticas extend e include las


cuales reciben un objeto, que en este caso ser una secuencia de
nombres de funcin y su funcin. La funcin extend se encargar
de generar las funciones estticas y la funcin include las funciones
de instancia, facil. Ahora vamos a ponerlo en prctica, imagina que
tienes un modulo que genera IDs aleatorios:
libjs.guid.coffee

libjs.guid =
generate: ->
'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace /[xy\
]/g, (c) ->
r = Math.random() * 16 | 0
v = if c is 'x' then r else r & 3 | 8
v.toString 16
.toUpperCase()

El mdulo libjs.guid y su funcin generate lo vamos a incluir


dentro una nueva clase Hero extendida de Module, y la vamos a
6. Modularizacin 67

utilizar en el constructor que se encargar de con cada instancia


tenga un atributo id que lo identifica:

class Hero extends Module


@include libjs.guid

constructor: (@name) ->


@id = @generate()
console.log "Instance with id #{@id}"

Parece sencillo no?, vamos a ponerlo en prctica creando un par de


instancias:

batman = new Hero "Batman"


> 'Instance with id 04C1E095-E1B9-475F-9D8D-48BD931AAD0\
4'

superman = new Hero "Superman"


> 'Instance with id 1EC75599-6CA7-490B-B3C1-F68CF468881\
4'

Como vemos la clase Module que pens Alex McCaw es tremen-


damente fcil de implementar y extensible horizontalmente ya que
puedes tener mdulos iguales que se incluyen en clases diferentes,
generando un cdigo as mucho ms mantenible. Por ponerte un
ejemplo mis proyectos Monocle y Atoms utilizan la class Module
y utilizan mdulos comunes, a pesar de ser proyectos diferentes.
https://github.com/soyjavi/monocle
https://github.com/tapquo/atoms
7. Bibliografa
En este captulo intento reunir toda la documentacin que un
CoffeeScripter tiene que leer para convertirse en un mejor desa-
rrollador. Muchos de los libros que aparecen en esta lista me han
ayudado a escribir este libro y por lo tanto me siento con el
compromiso de obligarte a leerlos a ti tambin.

JavaScript: The Good Partspor Douglas CrockFord (Oreilly)


- Comprar
Eloquent JavaScriptpor Marijn Haverbeke - Descargar
The little book of CoffeeScriptpor Alex McCaw (Oreilly) -
Comprar
CoffeeScript: Accelerated JavaScript Developmentpor Tre-
vor Burnham (The Pragmatic Programmers) - Comprar
CoffeeScript Cookbookpor David Brady & Co. - Online
Testing with CoffeeScriptpor Jack Franklin - Descargar
Clean Codepor Robert C. Martin (Prentice Hall) - Comprar

http://shop.oreilly.com/product/9780596517748.do
http://eloquentjavascript.net/
http://shop.oreilly.com/product/0636920024309.do
http://pragprog.com/book/tbcoffee/coffeescript
http://coffeescriptcookbook.com/
https://efendibooks.com/minibooks/testing-with-coffeescript
http://www.amazon.es/Clean-Code-Handbook-Software-Craftsmanship/dp/
0132350882

S-ar putea să vă placă și