#267 CoffeeScript Basics
- Download:
- source codeProject Files in Zip (84 KB)
- mp4Full Size H.264 Video (21 MB)
- m4vSmaller H.264 Video (12.2 MB)
- webmFull Size VP8 Video (14.2 MB)
- ogvFull Size Theora Video (33.9 MB)
CoffeScript es un lenguaje que genera JavaScript. Viene incluido por defecto con Rails 3.1 por lo que pronto muchos desarrolladores de Rails van a tener que echarle un vistazo por primera vez. Para empezar a aprenderlo en este episodio veremos cómo convertir código JavaScript ya existente a CoffeScript. El código que vamos a convertir es el que escribimos en el episodio 261 [verlo, leerlo] que validaba números de tarjeta de crédito.
Para aquellos que no hayan usado nunca CoffeeScript la web oficial es el mejor sitio por donde empezar. Allí encontraremos varios ejemplos de CoffeeScript así como el JavaScript en que se convierten. También hay una página donde podemos escribir código CoffeeScript y verlo convertido en JavaScript que luego podremos ejecutar en el navegador y todo mediante código en el cliente sin realizar llamadas AJAX al servidor.
El código JavaScript que vamos a convertir es el de la siguiente página, que se activa cuando un usuario sale del campo de número de tarjeta de crédito y que emplea la técnica de calcular el resto de dividir por 10 como validación básica del número introducido, mostrándose un mensaje de error junto al campo de texto si detecta que el número no es correcto.
A continuación mostramos el código JavaScript:
var CreditCard = { cleanNumber: function(number) { return number.replace(/[- ]/g, ""); }, validNumber: function(number) { var total = 0; number = this.cleanNumber(number); for (var i=number.length-1; i >= 0; i--) { var n = +number[i]; if ((i+number.length) % 2 == 0) { n = n*2 > 9 ? n*2 - 9 : n*2; } total += n; }; return total % 10 == 0; } }; $(function() { $("#order_credit_card_number").blur(function() { if (CreditCard.validNumber(this.value)) { $("#credit_card_number_error").text(""); } else { $("#credit_card_number_error").text("Invalid credit card number."); } }); });
La versión de Rails de esta aplicación es la 3.1 Release Candidate 1, que se anunció en el momento de escribir este episodio. Podemos actualizarnos a ella con gem install rails --pre
.
Los primeros cambios
Para cambiar un fichero JavaScript a CoffeeScript tan sólo tenemos que ponerle la extensión .coffee
al nombre de archivo. Por supuesto podemos seguir usando ficheros JavaScript normales con Rails 3.1 usando la extensión habitual .js
, el uso de CoffeeScript es completamente opcional.
Podemos empezar comentando todo el código JavaScript y cambiarlo paso a paso por su equivalente CoffeeScript. En la primera sección convertiremos la función cleanNumber
que limpiaba el número de tarjeta de crédito recibido eliminando los espacios y los guiones que vinieran.
var CreditCard = { cleanNumber: function(number) { return number.replace(/[- ]/g, ""); } }
El código CoffeeScript equivalente es:
CreditCard = cleanNumber: (number) -> number.replace /[- ]/g, ""
Con CoffeeScript nos ahorramos buena parte de la sintaxis de JavaScript. Al usar la tabulación para definir los niveles de bloque nos libramos de todas las llaves pero, eso sí, deberemos ser consistentes con el uso de los espacios en blanco.
También podemos dejar de utilizar la palabra clave var
y al final de una función no tenemos por qué usar return
: el último valor evaluado en la función se devuelve automáticamente, igual que en Ruby. No hace falta tampoco usar puntos y comas.
No hay tampoco que rodear con paréntesis los argumentos en las llamadas a función. La única excepción a esto es cuando se invoca una función sin argumentos, en cuyo caso CoffeeScript necesita los paréntesis para saber que se está invocando una función.
Por último cambia la forma en la que se invocan las funciones; hay que eliminar la palabra clave function
y cambiarla por ->
tras los argumentos de la función. Cuesta un poco acostumbrarse a esta forma tan concisa de definir funciones.
Con este fragmento de código ya convertido a CoffeeScript podemos compilarlo para ver qué JavaScript se genera. La salida se parece mucho a nuestro código original:
var CreditCard; CreditCard = { cleanNumber: function(number) { return number.replace(/[- ]/g, ""); } };
Echémosle un vistazo ahora a la función validNumber
de nuestro código JavaScript.
validNumber: function(number) { var total = 0; number = this.cleanNumber(number); for (var i=number.length-1; i >= 0; i--) { var n = +number[i]; if ((i+number.length) % 2 == 0) { n = n*2 > 9 ? n*2 - 9 : n*2; } total += n; }; return total % 10 == 0; }
Sigamos los mismos pasos para convertir este código a CoffeeScript.
validNumber: (number) -> total = 0 number = @cleanNumber(number) for i in [(number.length-1)..0] n = +number[i] if (i+number.length) % 2 == 0 n = if n*2 > 9 then n*2 - 9 else n*2 total += n total % 10 == 0
De nuevo hemos quitado las llaves y los punto y coma así como las palabras clave var
y return
, y por último hemos cambiado function
por ->
. También hemos hecho otros cambios para limpiar un poco el código.
Donde aparezca this
podemos poner el signo @
, de forma que this.cleanNumber
se convierte en @number
. Podemos también quitar las llaves de la sentencia if
porque tampoco hacen falta. El operador ternario también ha cambiado, por lo que podemos cambiar la interrogación y los dos puntos al estilo de C por una sentencia if then else
.
El resto del código tiene buen aspecto; sólo nos queda cambiar el bucle for
. En CoffeeScript los iteradores funcionan de forma distinta a JavaScript: podemos iterar sobre un array con código como este:
for number in [1,2,3] alert number
Esto genera el siguiente JavaScript:
var number, _i, _len, _ref; _ref = [1, 2, 3]; for (_i = 0, _len = _ref.length; _i < _len; _i++) { number = _ref[_i]; alert(number); }
Alternativamente podemos escribir el código de la siguiente manera y se traducirá al mismo JavaScript:
alert number for number in [1,2,3]
Para una secuencia de números podemos usar un rango en lugar de un array:
for number in [1..3] alert number
Con esto el JavaScript generado se simplifica:
var number; for (number = 1; number <= 3; number++) { alert(number); }
Si queremos que el bucle cuente hacia atrás tan sólo tenemos que darle la vuelta a los números del rango.
for number in [3..1] alert number
Esto se parece mucho a lo que hace el bucle for
de nuestro código, así que lo podemos reemplazar por una cuenta regresiva similar.
Ya sólo nos queda el último fragmento de código JavaScript.
$(function() { $("#order_credit_card_number").blur(function() { if (CreditCard.validNumber(this.value)) { $("#credit_card_number_error").text(""); } else { $("#credit_card_number_error").text("Invalid credit card number."); } }); });
Este fragmento de jQuery adjunto el código de validación al evento blur
del campo correspondiente al número de tarjeta de crédito. No hay que hacer nada especial para gestionar el código jQuery en CoffeeScript, el código equivalente es:
jQuery -> $("#order_credit_card_number").blur -> if CreditCard.validNumber(@value) $("#credit_card_number_error").text("") else $("#credit_card_number_error").text("Invalid credit card number.")
Igual que antes hemos cambiado las llaves y punto y coma, cambiado function
por ->
y las referencias a this
las hemos pasado a @
. Queda una última modificación que es cambiar la primera llamada a $
por jQuery
, que no surte ningún efecto a nivel de funcionalidad pero pone más de manifiesto que estamos usando jQuery.
Con todo el JavaScript cambiado a CoffeeScript recargamos la página en el navegador para ver si todo funciona igual que antes.
Y lo hace. Si introducimos un código incorrecto de tarjeta de crédito veremos el mensaje de error que desaparece tan pronto como introduzcamos un número válido. Al final del fichero JavaScript de nuestra aplicación veremos el código JavaScript que ha sido compilado a partir del fichero CoffeeScript.
(function() { var CreditCard; CreditCard = { cleanNumber: function(number) { return number.replace(/[- ]/g, ""); }, validNumber: function(number) { var i, n, total, _ref; total = 0; number = this.cleanNumber(number); for (i = _ref = number.length - 1; _ref <= 0 ? i <= 0 : i >= 0; _ref <= 0 ? i++ : i--) { n = +number[i]; if ((i + number.length) % 2 === 0) { n = n * 2 > 9 ? n * 2 - 9 : n * 2; } total += n; } return total % 10 === 0; } }; jQuery(function() { return $("#order_credit_card_number").blur(function() { if (CreditCard.validNumber(this.value)) { return $("#credit_card_number_error").text(""); } else { return $("#credit_card_number_error").text("Invalid ↵ credit card number."); } }); }); }).call(this);
Depuración
¿Qué ocurre si tenemos un error de sintaxis en nuestro código CofeeScript? Si cambiamos el fichero CoffeeScript para que tenga un error y recargamos la página en el naveador no veremos nada, porque la petición de JavaScript va aparte. Sin embargo si vemos en la consola de desarrollo veremos que el error sí aparece.
Aparece suficiente información en el mensaje de error como para indicar qué es lo que ha ido mal y qué línea de código debemos mirar para empezar a depurar el código.
Con esto cerramos este episodio. Todavía nos queda mucho por ver de CofeeScript, se recomienda visitar el sitio oficial de CofeeScript para leer más de este pequeño y divertido lenguaje.