Está en la página 1de 74

CoffeeScript

Un pequeño gran libro

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

Esta versión 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 día a día.
Í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 Interpolación 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. Modularización . . . . . . . . . . . . . . . . . . . . . . . 63
6.1 Namespacing . . . . . . . . . . . . . . . . . . . . . . 63
6.2 Mixins . . . . . . . . . . . . . . . . . . . . . . . . . . 64
6.3 Extendiendo clases . . . . . . . . . . . . . . . . . . . 65

7. Bibliografía . . . . . . . . . . . . . . . . . . . . . . . . . 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 dártelo; 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 día a día de nuestra loca empresa y
seguir con el propósito 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 país y
centrarme en este texto que ahora lees.
Dar las gracias también a Jeremy Ashkenas por crear el lenguaje
CoffeeScript y contribuir altruistamente a la evolución 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 código, más mantenible y más comprensi-
ble. Ahora solo te pido una última cosa, comparte este libro cómo lo
he hecho yo contigo, regálalo y ayúdame a transmitir este contenido
por el mundo.
¹http://tapquo.com
Prefacio
Tal vez no sabes muy bien porqué estás leyendo este pequeño 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 escribiéndolo.
Te preguntarás 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 más me he divertido mientras lo
descubría y el que más 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 también su propia génesis, comencemos.
La primera vez que escuché de CoffeeScript fue gracias a mi amigo
Guillermo Pascual³ cuando en Septiembre del 2011 estábamos en la
primera oficina de Tapquo desarrollando, y refactorizando, lo que
iba a ser la primera versión de LungoJS⁴. Al principio no le presté
mucha atención a CoffeeScript, pretendía ser mejor programador
en JavaScript y Lungo iba a ser mi primer gran exponente, tenia
puesto el Focus y no debía 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 pretendía, cuando dediqué mi tiempo
a CoffeeScript. Comencé leyendo varios libros, tampoco había
muchos más, 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 además de usarlo activamente
en nuestros locos días de oficina lo usan miles de desarrolladores
por todo el mundo.
Solo me queda pedirte una cosa, ¡diviértete!, diviértete 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 tendría un buen puñado de monedas
virtuales en mi bolsillo. JavaScript nunca ha sido, ni será, el lenguaje
de programación más utilizado y más famoso del mundo, para eso
tenemos a C o Java. Voy a ponerte en contexto, fue desarrollado
en apenas 10 días 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 versión ligera de Java para la web.
Lo que es seguro es que desde sus inicios en 1995 JavaScript ha
seguido en constante evolución:

• 1995 Primera versión


• 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
demás singularidades de la OOP, ni para los que solo han trabajado
con lenguajes modernos (Python, Ruby, Haskell…), que maldecían
la verbosidad barroca, con las conocidas llaves, paréntesis y puntos
y comas. Por lo tanto siempre ha sido criticado y en mi opinión
siempre lo será. Como todos los lenguajes, JavaScript tiene defectos,
pero poco a poco y con cada nueva revisión 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 propósito es que respetes al Lenguaje
Padre y que puedas enfrentarte a proyectos con las suficientes lineas
de código que asuste al mejor de los Gurus de jQuery⁸ (sarcasmo).

CoffeeScript, El hijo bastardo

CoffeeScript es un lenguaje de programación 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 escribirán
con menos lineas de CoffeeScript, mas o menos una proporción
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 añadían nuevas
características cada mes.
Después de publicarse la versión 1.0 en navidades del 2010, CoffeeS-
cript se convirtió en uno de los proyectos más seguidos en GitHub.
El lenguaje volvió a tener un empujón en la escena web, cuando en
Abril del 2011 David Heinemeier Hansson¹¹ confirmó los rumores
que decían que CoffeeScript iba a estar incluido en la versión 3.1 de
Ruby on Rails.
Y yo me pregunto ¿como puede ser que un lenguaje tan pequeño
haya captado tanto interés? Tres razones me vienen a la mente:
divertido, seguro y fácil de leer.

Un libro por el mundo

Este libro fue escrito durante mi viaje por Tailandia, en los meses
de Noviembre y Diciembre del año 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 propósitos 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 próximo libro tratará sobre EcmaScript 6¹² y lo escribiré en
Nueva Zelanda, por lo que si después de leer este libro te ha gustado
tanto como para hacer una donación¹³, financiando así parte del
próximo libro, te estaré eternamente agradecido.
¹²https://en.wikipedia.org/wiki/ECMAScript
¹³leanpub.com/coffeescript
1. Comenzando
Si has leído 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 años.
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 cuestión:
¿Cómo puedo ejecutar el compilador en mi sistema si todavía
no tengo el compilador de CoffeeScript?
¿No? Te voy a ayudar a encontrar la solución preguntándote de
nuevo; si hubiera una manera de ejecutar JavaScript en tu maquina
sin utilizar un navegador web y mostrar el código al sistema
operativo… ¿Sigues sin caer? ¿De verdad?
Es muy sencillo, no hace falta más que utilizar NodeJS¹⁴ y he
aquí donde viene un punto de aclaración; mucha gente entiende
“Node” como un servidor web en JavaScript pero, por suerte, es
mucho más que eso y cada vez está más presente en soluciones
que nada tienen que ver con el mundo de los servidores web.
Fundamentalmente NodeJS es un puerta entre tu código 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 analogía 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 más y quieres intentar codificar tus
primeras lineas en CoffeScript echa un pequeño vistazo al Try
CoffeeScript¹⁶ de la página oficial.

1.2 Instalando NodeJS

Existen dos formas de instalar nodeJS, mediante el código fuente


del proyecto (y su posterior compilación) o bien descargando una
instalación con el proyecto ya compilado. Independientemente del
sistema operativo que uses no tendrás grandes problemas, pero si
que puedo decir que por mi experiencia los que más problemas
suelen tener con la instalación 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 tendrás 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 añadir 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 instalación 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 sección 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 pequeño programa para comprobar que todo


está funcionando correctamente, antes de ello ejecuta el siguiente
comando para comprobar la versión de la que dispones:

node -v

Ahora viendo que tienes una versión reciente (por tu bien) vas a
crear un pequeño 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 deberías 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 dirección 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 instalación 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 parámetros


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 instalación debes comprobar que versión de CoffeeScript
tienes en el sistema:

coffee -v

Si aparece una nueva versión de CoffeeScript la actualización


es relativamente sencilla ya que únicamente tienes que volver a
utilizar NPM cambiando un único parámetro ¿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 función 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 capítulo,


aunque por la sintaxis y los operadores puedes llegar a sacar una
conclusión. En el siguiente capitulo vas a conocer más de la sintaxis
de este lenguaje y descubrirás lo bien hecho que está y lo divertido
que es programar con el.
2. Sintaxis
Antes de comenzar con este capítulo asumo que tienes una base en
JavaScript, y eso no quiere decir que sabes usar jQuery o cualquier
otra librería. 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 descubrirás algunas particularidades del lenguaje JavaS-


cript y siempre te vendrá bien tenerlos a mano para poder repasar
algún que otro concepto. En este capítulo vamos a aprender la
sintaxis básica de CoffeeScript comprobando que comparte más
similitudes con Ruby o Python que con JavaScript.

2.1 Valores, variables y comentarios

La creación y asignación de variables no difiere mucho de otro len-


guaje de programación, tal vez la mayor diferencia con JavaScript
es que no hace falta comenzar con var ni finalizar la declaración
con el prehistórico 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 capítulo conocerás como CoffeeScript


gestiona automáticamente el ámbito de nuestras variables, escapan-
do del temido e ineficiente GlobalScope.
En el caso de que necesites introducir cadenas de texto de mayor
tamaño podríamos 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 increíble 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
darán 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
prehistóricas 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 código siguen el mismo patrón,


utilizando el carácter # como delimitador:

# Tu primer comentario

Los comentarios multilinea también están 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 código fuente.
###

2.2 Interpolación de cadenas

CoffeeScript nos da la interpolación de string de una manera


similar a como lo hace Ruby. Dentro de una cadena delimitada por
el caracter " podremos introducir la expresión #{}, la cual puede
contener cualquier tipo de expresión 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 más completo con operaciones


numéricas donde descubrirás algo más 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 opinión la interpolación es una solución mucho más elegante


que la concatenación 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 aplicación, recordando que CoffeeScript esta lleno de
convenciones que facilitan la escritura de buen código. Por ejemplo,
no es necesario utilizar paréntesis 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


indentación donde solo hay una linea born = true, aunque
podrías introducir todas las que necesites, además vemos que no
es necesario introducir () y {}. Se recomienda que cada nivel de
indentación 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 código. De todas formas,
podemos hacerlo de una forma más 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 código
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 operación 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 expresión más, por ejemplo en el caso


de que solo necesites hacer una comparación if podríamos hacerlo
al estilo Ruby:

born = true if year is 1980

Si quisiésemos hacer la negación de la sentencia anterior, esto


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

born = false if year isnt 1980

o también utilizando la expresión 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 más adelante podrás
conocer más alias disponibles en CoffeeScript los cuales aportarán
una mayor expresividad a tu código.

2.4 Loops

Una de las estructuras que más solemos utilizar como desarrolla-


dores son las iteraciones o bucles, esto se expone claramente en los
proyectos JavaScript donde al no existir muchos métodos dedicados
para el tratamiento de arrays debemos leer el contenido de los
mismos de forma iterada.
En CoffeeScript vas a empezar por lo básico, pero en capítulos
posteriores podrás ver que disponemos de hacks dedicados a los
arrays los cuales te solventarán la vida. Vamos a ver como podrías
crear un simple bucle contador con la expresión while:
2. Sintaxis 19

heroes = 0
while heroes <= 12
heroes++

En mi opinión 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
expresión then:

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

También podemos utilizar la expresión until para hacer llegar al


mismo resultado y tal vez dandole mayor expresividad a nuestro
código:

heroes = 0
until heroes is 12 then heroes++

Si por el contrario quieres recorrer un Array (más adelante dedicaré


una sección completa a los Arrays) deberemos utilizar la expresión
for combinándolo 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 expresión by seguido del incremento numérico:

²¹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 más, 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 código resultante en JavaScript, para comprobar


que las estructuras que genera CoffeeScript son totalmente correc-
tas, respetando declaración 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 expresión 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 algún condicionante dentro de el
y demos por finalizo el proceso con la expresión 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 expresión break ejecuta la linea inmediata a
la estructura loop. Vamos a echar un vistazo a como quedaría el
código 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


código expresivo, por ahora hemos visto algunos operadores como
is, isnt, unless y desde esta sección conoceremos más facilitadores
para nuestro código CoffeeScript.
Como ya sabes is es traducido al comparador === y su contrario
isnt es traducido a !==, en el caso de que quieras hacer una
negación ! deberás 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 habrás dado a ti mismo ha sido or y and. Bien, pues
CoffeeScript intenta crear lenguaje natural en tu código 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 también 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 más preciso, dado que si la variable location no esta declarada
dará un error de compilación. Utilizando ? nos aseguramos que
comprueba que location no sea ni undefined ni null:

where = location ? "Gotham"

Veamos como queda esta mínima sentencia en JavaScript:

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

El operador existencial ? te puede servir para muchos más con-


textos, por ejemplo imagina que tienes una librería basada en
módulos y quieres llamar a un método 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 método
batMobile. Traduciendo la anterior sentencia a JavaScript quedaría
de la siguiente manera:

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

Imagina ahora que quieres ejecutar el método kamehame siempre


y cuando sea una función ejecutable, simplemente cambiando la
posición del operador ? lo tendrás resuelto:

goku.movements?.kamehame?()

Echa un vistazo a su traducción en JavaScript:

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

Uno de los alias que más me sorprendió cuando aprendí CoffeeS-


cript fue @ el cual se utiliza para sustituir el típico 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 próximo
artículo 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 capítulo 5, clases,
darémos un pequeño repaso al paradigma de los prototipos en
JavaScript con CoffeeScript.
3. Funciones, Ámbito y
Contexto
CoffeeScript elimina todo adorno barroco en la declaración de
funciones tal y como estás acostumbrado en la programación con
JavaScript. Lo sustituye por un símbolo simple y conciso como es ->
y como verás más adelante deberás 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
función ya que existe una convención donde la última expresión que
definamos dentro de una función automáticamente 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 función
necesite devolver algo antes.

3.1 Funciones

Como vale más un ejemplo que mil palabras, con la siguiente linea
te descubro tu primera función en CoffeeScript:

hello = -> “world”

Como puedes ver he creado una función llamada hello la cual


devuelve automáticamente la cadena de texto “world”, lo se, no es
una función 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 múltiples lineas.
Pero la función hello podría codificarse de la siguiente manera:

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

La compilación en JavaScript seguirá siendo exactamente igual que


en la primera función hello, por lo que en este punto tu decidirás
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 declaración de funciones es sumamente


sencilla, pero el ejemplo anterior es poco versátil ya que únicamente
devuelve un valor constante. Veamos una función algo más dinámi-
ca:

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

En esta ocasión tenemos una función 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 más cuesta en JavaScript es el control de


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

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

Como ves sigue siendo muy sencillo y curiosamente sigue siendo


una sola linea de código, pero si analizamos la compilación en
JavaScript:

var divide;

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

Si estudiamos el código vemos que controla si el argumento b es


null, en caso de que lo sea automáticamente 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 símbolo ... (splats)


detrás 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 enseñar cuando doy charlas sobre


CoffeeScript, es demostrar la enorme flexibilidad que tiene para
controlar la entrada de argumentos en una función. Por ejemplo,
tenemos una función 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 automáticamente los convierta en un array de
elementos, siempre y cuando existan valores. Como vemos en el
ejemplo continuamos con la declaración de funciones en una única
linea pero si leemos el código 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 más allá, veamos como crear un sandwich
combinando argumentos:

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

Los argumentos que no son de tipo splat se asignarán en primer


lugar, por lo que si se llama a sandwich con dos únicos argumentos,
estos pasarán a top y base. Sólo cuando hay tres o más argumentos
se utilizará el argumento splat ingredients y con esto CoffeeScript
vuelve a reafirmarse con la convención “simplicidad frente a com-
plejidad”.
Recordarte, como buen conocedor de los internals de JavaScript,
que también podríamos no declarar ningún argumento y acceder a
ellos gracias al array arguments:
3. Funciones, Ámbito y Contexto 31

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

Aprovecho esta función para recordarte la interpolación por medio


de #{} que aprendiste en el capítulo anterior, acostúmbrate a
utilizarla siempre que puedas. Veamos como quedaría la función
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 todavía 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 paréntesis ni punto y coma para


declarar el limite de los argumentos de una función, si compilamos
a JavaScript sería:

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 método de JavaScript alert:
3. Funciones, Ámbito y Contexto 32

alert divide 1, 2

Fíjate 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 más, imagínate que tenemos una fun-


ción 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 función sin delimitar la propia función ni


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

var hero;

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

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

Todavía no hemos visto como llamar a una función sin argumentos,


y en esta ocasión se hace igual que en JavaScript utilizando nuestros
queridos (sarcasmo) e inseparables paréntesis:
3. Funciones, Ámbito y Contexto 33

hello()

También 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 más expresividad a mi código:

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 despreocupación en JavaScript
nos puede llevar a futuros problemas dentro de nuestra aplicación
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 función restartGame no
ha tenido ningún efecto sobre la variable lifes. ¿Cómo 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 fácil su ámbito se define gracias a tres sencillas
reglas:

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


ámbito es definiendo una función.
• El ciclo de vida de una variable perdurará en el ámbito más
externo en el que se ha hecho una asignación 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 función restartGame, y en el último


ejemplo, solo existía dentro de la función restartGame. Es por
eso que tenemos un ReferenceError sobre lifes tratando de ser
utilizada fuera de la función restartGame, puesto como habrás
podido descubrir la variable no existe.
En CoffeeScript al ámbito se conoce como ámbito léxico, y real-
mente es el mismo que en JavaScript, salvo que en este último la
declaración del ámbito va asociada a la palabra reservada var y en
CoffeeScript el ámbito se define con la primera asignación. Esto
te ahorra tiempo a la hora de desarrollar tu código, 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 más interno. La otra manera es como argumento de una
función:

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 función insertCoin,


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

como parámetro y el cometido de esta operación es únicamente


devolver el resultado de la operación, el cual no se asigna a lifes.
El shadowing normalmente esta considerado un mala praxis en
programación 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 preguntarás, “¿Cómo puedo asignar a una variable
el ámbito correcto sin realizar una asignación?” La respuesta es que
en CoffeeScript es imposible. En lugar de eso tendrás que realizar
una asignación 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 están 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 recién llegados al mundo de JavaScript y CoffeeScript a menudo
se encuentran con un desconcertante y poco descriptivo this. Uti-
lizándolo correctamente, te sientes verdaderamente un verdadero
SuperHeroe dispuesto a salvar al mundo. Usándolo erróneamente,
puede ser sin lugar a duda un enorme foco de errores. Parte de la
confusión 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 verás más adelante, el contexto, this/@,
puede ser totalmente diferente cada vez que se llame a una función.
Para los ejemplos utilizaremos un simple método createPower:
3. Funciones, Ámbito y Contexto 37

createPower = (power) -> @power = power

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


power, que podrías haberla llamado como quisieses, es una variable
local y nunca se verá fuera de la función createPower, mientras que
@power es una propiedad del contexto.
El objetivo principal de contexto es dar a los métodos de un objeto
(en funciones añadidas 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 método createPower que habíamos creado antes con el objeto
hero como contexto; por lo que @ en la función se refiere al objeto
hero, por lo que creará un atributo @name haciendo referencia a
hero.name. La función en si no ha cambiado, y podríamos 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 añadir la función a ningún


objeto en particular y utilizar los métodos call o apply propios de
la función (y qué como sabes todas las funciones JavaScript tienen).
El método 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 método call funciona exactamente igual, excepto por que recibe


un solo argumento y no un array. De esta manera apply es mucho
más versátil 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 función un contexto


y es utilizando la palabra reservada new, el cual creara un nuevo
objeto utilizando la función 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 estarás dando cuenta la palabra new no está devolviendo


el resultado de la función createPower, en cambio crea un nuevo
objeto, ejecuta la función 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


función, el contexto es el nuevo objeto.
3. Funciones, Ámbito y Contexto 39

• Cuando ejecutas una función mediante call o apply, el


contexto es el primer argumento.
• Si una función 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 función se ejecuta
en el contexto global.

3.6 Cambio de contexto en funciones

Los cambios de contexto son algo común en JavaScript, especial-


mente en los callbacks de eventos, por lo qué CoffeeScript nos
brinda la posibilidad de manejar esta situación muy facilmente.
Lo más común dentro de una función es la variación de -> por la
llamada Flecha Ancha o RocketArrow =>.
Usando => en vez de la Flecha Fina -> te aseguras que el contexto
de la función será el local. Por ejemplo:

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

La razón 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 código JavaScript, te voy a enseñar
la compilación 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 podríamos
acceder a la función 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 capítulo, en mi opinión junto con


las Clases (que veremos en un capítulo futuro) el tratamiento de
Funciones es el area más 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 habías 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 aprenderás como utilizar
las listas, las cuales te darán un buen mecanismo para ordenar nues-
tros datos. Desde aquí comenzaremos con las estructuras iterativas
loop, las comprensiones y la creación directa de arrays gracias a
ellas. Selección 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 más simple se escribiría:

var object = new Object();

Aunque comúnmente se suele utilizar la sintaxis heredada de JSON²³:

var object = {};

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


en el capítulo 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 notación simple . o con la notación tipo bracket {}. La primera es
sumamente sencilla de utilizar: obj.x hace referencia a la propiedad
x del objeto obj. La notación via bracket es mucho más versátil,
puesto que cualquier expresión que se incluya entre los brackets
se evaluará y converirá a un string utilizándose como nombre de
propiedad, veamos el mismo ejemplo obj['x']
Normalmente, utilizarás la notación por punto si conoces el nombre
de la propiedad previamente y en el caso de que lo tengas que
determinar dinámicamente utilizarás la notación 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
más 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 invocación de funciones, CoffeeS-


cript nos permite aligerar nuestro código dejándonos a nuestra
4. Objetos y Arrays 43

elección la utilización de los caracteres {}. Personalmente, las quito


siempre y además utilizo el nivel de indentación con las nuevas
lineas como sustituto del separador , de propiedades:

numbers =
one: 1
two: 2

Con la exclusión completa de {} y , conseguimos que nuestro objeto


sea más parecido a un YAML²⁴:

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

Este ejemplo seguro que te hará sonreír ademas de ver el verdadero


potencial de la creación 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 estás haciendo referencia a un objeto.
Esta técnica es especialmente útil cuando una función 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 ocasión vamos a crear un objeto que tenga una función
toString que devuelva serializado alguna de las propiedades de
nuestro objeto. Veamos como:

podcast =
number : 11
title : '¿Porqué es difícil testear?'
description: 'Conversación 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
más de CoffeeScript. Una de las cosas que siempre recomiendo a la
hora de trabajar con CoffeeScript es ver el código compilado para
analizar las estructuras JavaScript que genera, analicemos pues:
4. Objetos y Arrays 45

var podcast;
podcast = {
number: 11,
title: '¿Porqué es difícil testear?',
description: 'Conversación 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
notación 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 expresión 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 indentación como
delimitador de elementos y podrás 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 pensarás que no puedo hablar mucho más de Arrays,


nada más lejos de la realidad a partir de ahora voy a poner
casos de uso en combinación con funcionalidades de JavaScript y
CoffeeScript.

Obtener el valor máximo de un array

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


máximo, seguramente ahora estarás pensando en una iteracción en
JavaScript, una variable que va quedándose con el mayor numero
y al final de la iteracción (evidentemente) tendrás 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 fíjate que utilizo la
elipsis ..., una técnica muy utilizada para pasar un gran numero
de argumentos a una función.

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 pondrás 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 función map que nos permite


hacer operaciones con los elementos de un array. Como puedes
leer, porque una cosa que nos da CoffeeScript es la comprensión sin
conocimiento, en el nuevo array heroes solo existirán 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 dimensión de cada
objeto, con un nivel de indentación (fijate que la , esta en un nivel
inferior).
Los mapeos son una buena herramienta para manejar transforma-
ciones más complicadas que la que hemos realizado, más adelante
conocerás otra manera de hacerlo por medio de comprensiones.

Reduciendo Arrays

Imagina, tenemos un array de elementos y nos gustaría hacer algún


tipo de operación 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'

También podríamos hacer algo más 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 métodos reduce y reduceRight se introdujeron en la versión 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-
mérica. Deja de hacer más 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 numérica 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 código:

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

Filtrando Arrays

Imagina, necesitas filtrar un array por una determinada condición


booleana.

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

En el método filter vemos que define como parámetro una fun-


ción en la cual estamos pidiendo que se quede con los núme-
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 función de JavaScript, pero mucha gente


no la utiliza y es realmente util. La gran diferencia con el método
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 operación que los desarrolladores de
Python podrán reconocerlas fácilmente. Vamos a volver a realizar
un mapeo mediante comprensión 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 más sencillo que utilizar el método map


y sobre todo la creación del array heroes es realmente comprensible
(léelo y dime que no).
4. Objetos y Arrays 51

Si todavía 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 código:

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 además 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 función de filtrado. Ahora ya puedes ir a tu
consola de CoffeeScript para jugar con tus heroes y comprensiones.
Si todavía no estas impresionado por esta capacidad que tiene este
lenguaje, solo me queda sorprendente con una implementación del
mítico FizzBuzz en una única linea:

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


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

Esta implementación no es mía, 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 más famoso que utiliza el
paradigma basado en prototipos, y los demás 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 abstracción mucho mayor.
Desde este capítulo daremos un pequeño repaso a los prototipos y
nos meteremos de lleno en la creación 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 prototípico 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 método
prototípico says, veamos como:

Hero = (@power) ->


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

Comenzamos declarando Hero, recuerda que existe una convención


para que las bases tengan la primera letra en mayúscula, 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 función, y en


javascript, toda función es un objeto y como cualquier objeto tiene
propiedades y métodos. Una función, por defecto, tiene una serie
de propiedades, como: length, constructor, prototype y algunos
métodos como: call, apply, entre otros. Cualquier función es
susceptible de convertirse en un constructor, basta con anteponer
el operador new a la llamada de la función.
Ahora vamos a crear un par de superheroes, perdón, un par de
instancias Hero estableciendo a cada una de ellas su superpoder y
llamando al método 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 podías prever cada instancia de Hero dice que tiene un poder
distinto porque el método 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 estáticos:

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). Además creamos un atributo de instancia @number que
nos devolverá el valor interno de Hero.count, la última sentencia
del constructor será llamar automáticamente al método prototípico
says demostrando que todo lo creado funciona. El resultado sería:
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 función heredada @says

Recuerda que todas las funciones del nuevo objeto se ejecutarán en


el contexto del propio objeto, aunque en el capítulo 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 creación de una
clase. Ahora vamos a crear nuestra primera clase Hero:

class Hero

Como ves la simpleza es máxima y sobre todo entendible y com-


parable con otros lenguajes de programación. Vamos a ver como
quedaría 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 abstracción de la base prototípica,
permitiéndonos escribir código mucho más 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'

Compilándose 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 declaración entre métodos


estáticos y métodos de instancia o prototípicos, 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 función
de instancia says. ¿Por qué CoffeeScript sabe que el método 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 métodos de instancia debes utilizar el operador : junto
con el nombre del método que deseas crear. En nuestra clase hemos
creado 2 métodos: 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 método estático para la clase Hero,
por ejemplo vamos a crear un método 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 según vas creando instancias, podrás llamar


al método 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 implementación de clases de CoffeeScript no estaría completa


sino hubiese ningún 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 vehículos 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 vehículo y heropara indicar el nombre del
heroe dentro del vehículo. Por último he declarado un método 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 método 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 vehículo:
5. Clases 60

batmobile = new BatMobile()


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

Ahora voy a crear otro vehículo y voy a sobreescribir la variable


fuel en la nueva clase y así podré ver el diferente comportamiento
del método 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 método 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 vehículo vamos a crear un método 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


estáticas se copian en las subclases, en lugar de estar heredadas por
referencia. Esto es debido a la arquitectura e implementación de los
prototipos de JavaScript, y desgraciadamente es un problema difícil
de solucionar.

5.4 Polimorfismo

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


un concepto de la programación orientada a objetos el cual podría
decirse que en esencia refiere al comportamiento de los objetos, no
a su pertenencia a una jerarquía 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 método abstracto


burnout el cual si intentamos llamarlo desde una nueva instancia
de esta clase nos dará una excepción. Este método se utilizará en las
subclases de Vehicle y nos devolverá el numero de kilómetros que
puede recorrer el vehículo al ejecutar el método:
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 método burnout realiza diferentes operaciones
puesto que el consumo de los vehículos 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 función 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 expresión instanceof. En el caso de que sea una
instancia válida devolverá por consola el resultado de la función
burnout.
6. Modularización
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 Albedrío haga acto de presencia, creando
estructuras incorrectas, inmantenibles y peligrando el GlobalScope.
Se que esto puede darse en todos los lenguajes de programación,
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 capítulo he intentado reunir algunos puntos interesantes
que tienes que tener en cuenta para tener un código organizado y
mantenible; independientemente del patrón de diseño que utilices.

6.1 Namespacing
Como ya vimos en capítulos anteriores, todas las variables que se
declaran en una función solo existen en el ámbito propio de la
función. Cada nuevo fichero que compila CoffeeScript a su vez
genera una función autoejecutable, con su propio ámbito, y por
lo tanto si tenemos dos ficheros las variables de un fichero no
serán visibles desde el otro, a menos que estén 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 ¿cómo podemos acceder a esas funciones
y variables que tenemos en módulos 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. Modularización 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 módulos 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 deberás utilizar algún patrón
de diseño; siempre adecuado a la naturaleza de tu proyecto.

6.2 Mixins

Los llamados mixins²⁶ no están soportados de forma nativa en


CoffeeScript, por la sencilla razón de que son triviales y cada
²⁶http://en.wikipedia.org/wiki/Mixin
6. Modularización 65

desarrollador hace su propia implementación; algo parecido a lo


que pasa con el patrón 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 estáticas 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 patrón para compartir lógica de negocio
común entre diferentes módulos de tu aplicación. La ventaja de los
mixins es que puedes incluirlo en más de un objeto o clase, mientras
que comparándolo 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. Modularización 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 estáticas extend e include las


cuales reciben un objeto, que en este caso será una secuencia de
nombres de función y su función. La función extend se encargará
de generar las funciones estáticas y la función include las funciones
de instancia, facil. Ahora vamos a ponerlo en práctica, 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 módulo libjs.guid y su función generate lo vamos a incluir


dentro una nueva clase Hero extendida de Module, y la vamos a
6. Modularización 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 práctica 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 fácil de implementar y extensible horizontalmente ya que
puedes tener módulos iguales que se incluyen en clases diferentes,
generando un código así mucho más mantenible. Por ponerte un
ejemplo mis proyectos Monocle²⁸ y Atoms²⁹ utilizan la class Module
y utilizan módulos comunes, a pesar de ser proyectos diferentes.
²⁸https://github.com/soyjavi/monocle
²⁹https://github.com/tapquo/atoms
7. Bibliografía
En este capítulo intento reunir toda la documentación 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 también.

• 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

También podría gustarte