ES6 en Detalle: Funciones flecha

3 octubre, 2015 7:27 por

Esta es una traducción del artículo original publicado en el blog de Mozilla Hacks.

Las flechas han sido parte de JavaScript desde el comienzo. El primer tutorial de JavaScript recomendaba encerrar scripts en línea en comentarios HTML. Esto era para prevenir que los navegadores que no soportaban JavaScript mostraran erróneamente tu código como texto. Necesitabas escribir algo como esto:

Los navegadores viejos verían dos etiquetas no soportadas y un comentario; solo los nuevos navegadores verían código JS.

Para soportar este extraño hack, el motor JavaScript en tu navegador trata los caracteres <!-- como el comienzo de un comentario de línea. No es broma. Esto de verdad ha sido parte del lenguaje todo este tiempo, y ha funcionado hasta hoy día, no solo en el tope de línea <script> si no en todos lados en un código JavaScript. Incluso funciona en Node.

Da la casualidad que este estilo de comentarios fue estandarizado por primera vez en el ES6. Pero no es esta flecha de la que vinimos a hablar.

La flecha --> también denota un comentario de línea. De forma extraña, mientras en HTML los caracteres antes del --> son parte del comentario, en JavaScript el resto de la línea después de --> es el comentario.

Y solo se pone mas extraño. Esta flecha indica un comentario solo cuando está al inicio de la línea. Esto es porque en otros contextos, --> es un operador en JavaScript, el operador “tiende a”.

function cuentaRegresiva(n) {
  while (n --> 0)  // "n tiende a 0"
    alert(n);
  despegue();
}

Este código en verdad funciona. El ciclo corre hasta que n llegue a 0. Esto tampoco es algo nuevo en el ES6, sino más bien una combinación de características familiares, con un poco de engaño. ¿Te puedes dar cuenta de lo que sucede aquí? Como es usual, la respuesta a este problema se encuentra en Stack Overflow.

Claro, aquí también se encuentra el operador «menor o igual», <=. Encontrarás muchas flechas en tu código JavaScript, como en un juego de búsqueda, pero vamos a detenernos aquí y a observar que una flecha no aparece.

  • <!--- Comentario en línea
  • --> Operador “tiende a”
  • <= Menor o igual a
  • => ???

¿Que le paso a =>? Hoy, lo descubriremos.

Primero, hablemos un poco sobre funciones.

Las expresiones de función están en todos lados

Una característica divertida de JavaScript es que en cualquier momento que necesitas una función, puedes simplemente escribir la función en medio del código.

Por ejemplo, supongamos que estamos intentando decirle al navegador qué hacer cuando el usuario haga click en un botón en particular. Comienzas escribiendo:

$("#confetti-btn").click(

El método .click() de jQuery toma un argumento: una función. No hay problema. Simplemente puedes escribir tu función ahí mismo:

$("#confetti-btn").click(function (event) {
  reproducirTrompeta();
  dispararCanonDeConfetti();
});

Escribir código como este nos parece natural hoy día. Es extraño recordar que antes de que JavaScript popularizara este tipo de programación, muchos lenguajes no tenían esta característica. Claro Lisp tenía expresiones de función, llamadas funciones lambda, en 1958. Pero C++, Python, C#, y Java existieron por años sin ellas.

Nunca más. Todos tienen lambdas ahora. Los lenguajes nuevos universalmente tienen lambdas en su núcleo. Tenemos que agradecerle ésto al JavaScript – y los primeros programadores de JavaScript quienes sin miedo construyeron librerías que dependían en gran parte en lambdas, llevando a que se expandiera la adopción de esta característica.

Es un poco triste, entonces, que de los lenguajes que mencionamos, la sintaxis de JavaScript para los lambdas es la más larga.

// Una función muy simple en los 6 lenguajes que mencionamos.
function (a) { return a > 0; } // JS
[](int a) { return a > 0; } // C++
(lambda (a) (> a 0)) ;; Lisp
lambda a: a > 0 # Python
a => a > 0 // C#
a -> a > 0 // Java

Una nueva flecha en tu funda

ES6 introdujo una nueva sintaxis para escribir funciones.

// ES5
var selected = allJobs.filter(function (job) {
  return job.isSelected();
});

// ES6
var selected = allJobs.filter(job => job.isSelected());

Cuando necesites una función simple con un solo argumento, la nueva sintaxis de función flecha es simple: identificador => expresión. Te evitas escribir function y el return, así como algunos paréntesis, llaves y punto y coma.

(Estoy personalmente muy agradecido de esta característica. No tener que escribir function es importante para mí, porque yo inevitablemente escribo functoin y tengo que regresar y corregirlo.)

Para escribir funciones con múltiples argumentos (o sin argumentos, o parámetros restantes o por defecto, o argumentos de desestructuracion) necesitarás agregar paréntesis en la lista de argumentos.

// ES5
var total = values.reduce(function (a, b) { return a + b; }, 0);

// ES6
var total = values.reduce((a, b) => a + b, 0);

Creo que se ve muy bien así.

Las funciones flecha funcionan hermosamente con herramientas funcionales otorgadas por librerías como Underscore.js e Immutable. De hecho, los ejemplos en la documentación de Immutable todos están escritos en ES6, y muchos de ellos ya usan funciones flecha.

¿Qué hay acerca de las configuraciones no tan funcionales? Las funciones flecha pueden contener un bloque de sentencias en lugar de una simple expresión. Recordamos nuestro ejemplo anterior:

// ES5
$("#confetti-btn").click(function (event) {
  reproducirTrompeta(); 
  dispararCanonDeConfetti();
});

Así se vería en el ES6:

// ES6
$("#confetti-btn").click(event => {
  reproducirTrompeta();
  dispararCanonDeConfetti();
});

Una mejora menor. El efecto en el código usando Promises puede ser más dramático, como las líneas }).then(function (result){ se apilan.

Noten que las funciones flecha con bloques no retornan automáticamente un valor. Usa la sentencia return para eso.

Hay una advertencia cuando usamos funciones flecha para crear objetos planos. Siempre encierra el objeto en un paréntesis:

// Crea un nuevo objeto para que cada perro juegue.
var juguetes = perros.map(perro => {});   // BUG!
var juguetes = perro.map(perro => ({})); // ok

Desafortunadamente, un objeto vacío {} y un bloque {} se ven exactamente igual. La regla en ES6 es que { inmediatamente siguiendo una flecha es siempre tratado como un el comienzo de un bloque, nunca como el comienzo de un objeto. El código perro => {} es entonces interpretado como una función flecha que no hace nada y retorna undefined.

Más confuso aun, un objeto literal como {key: value} se ve exactamente igual a un bloque conteniendo un sentencia etiquetada – al menos, eso es como se ve en tu motor JavaScript. Afortunadamente { es el único carácter ambiguo, así que encerrar el objeto con paréntesis es el único truco que necesitarás recordar.

¿Qué es this?

Hay una diferencia en el comportamiento de las funciones ordinarias y las funciones flecha. Las funciones flecha no tienen su propio valor this. El valor de this dentro de una función flecha siempre es heredado del ámbito circundante.

Ante de que intentemos darnos cuenta de lo que significa en la práctica, demos un paso atrás.

¿Cómo funciona this en JavaScript? ¿De donde viene este valor? No hay respuesta corta. Si parece simple en tu cabeza, ¡es porque has estado usándolo por mucho tiempo!

Una razón por la que esta pregunta aparece con frecuencia es que las funciones ordinarias reciben el valor de this automáticamente, lo quieran o no. ¿Has escrito este hack alguna vez?

{
  ...
  addAll: function addAll(pieces) {
    var self = this;
    _.each(pieces, function (piece) {
      self.add(piece);
    });
  },
  ...
}

Aquí, lo que te gustaría escribir en la función interna es simplemente this.add(piece). Desafortunadamente, la función interna no hereda el valor de this que esta fuera de la función, this será window o undefined. La variable temporal self sirve para contrabandear el valor de this a la función interna. (Otra manera es usar .bind(this) en la función interna. Ninguna de ellas es muy bonita.)

En el ES6, los hacks para manejar a this desaparecen si se siguen estas reglas:

  • Usa funciones no-flecha para métodos que se llamen usando la sintaxis object.method(). Aquellas son funciones que recibirán valores útiles de this del invocador.
  • Usar funciones flecha para todo lo demás.
// ES6
{
  ...
  addAll: function addAll(pieces) {
    _.each(pieces, piece => this.add(piece));
  },
  ...
}

En la versión ES6, nota que el método addAll recibe this del que lo ha llamado. La función interna es una función flecha, así que hereda el valor de this del que lo encapsula.

Como un bonus, ES6 también provee una manera más corta de escribir métodos en los literales de objeto. Así que el código de arriba se puede simplificar más aún:

// ES6 con el método de sintaxis nuevo
{
  ...
  addAll(pieces) {
    _.each(pieces, piece => this.add(piece));
  },
  ...
}

Entre los métodos y flechas, quizás nunca escribiré functoin de nuevo. Es un bonito pensamiento.

Hay otra diferencia menor entre las funciones flecha y las funciones no-flecha: las funciones flecha no obtienen el objeto arguments, tampoco. Claro en el ES6 probablemente utilizarás parámetros restantes o por defecto de cualquier modo.

Usando flechas para atravesar el oscuro corazón de la informática

Hemos hablado de las muchos usos prácticos de las funciones flecha. Hay un posible caso del que me gustaría hablar: Las funciones flecha del ES6 como herramientas de aprendizaje, para descubrir algo profundo acerca de la naturaleza de la computación. Donde si es practico o no, deberás decidirlo por ti mismo.

En 1936, Alonzo Church y Alan Turing independientemente desarrollaron poderosos modelos matemáticos de computación. Turing llamó su modelo a-machines, pero todos instantáneamente lo comenzaron a llamar máquinas de Turing. Church escribió en su lugar acerca de funciones. Su modelo fue llamado cálculo λ. (λ es la letra griega Lambda.) Este trabajo fue la razón que Lisp utilizara la palabra LAMBDA para denotar funciones, y ese es el por qué llamamos a las expresión de función “lambdas” hoy día.

¿Pero qué es el cálculo λ? ¿Qué significa “modelo de computación”?

Es un poco difícil de explicar en pocas palabras, pero aquí va un intento: el cálculo λ es uno de los primeros lenguajes de programación. No fue diseñado para ser un lenguaje de programación – después de todo, las computadoras con programas almacenados no llegarían en una o dos décadas. En lugar de eso tenemos una idea simple y despojada, de un lenguaje matemático que puede expresar cualquier tipo de computación que desees. Church quería este modelo para probar cosas de computación en general.

Y el descubrió que solo se necesitaba una cosa en su sistema: funciones.

Piensa cuán extraordinario es esto. Sin objetos, sin arreglos, sin números, sin if, while, punto y comas, asignaciones, operadores lógicos, incluso sin ciclos de eventos. Es posible recrear cualquier tipo de computación que JavaScript puede hacer, desde cero. Usando solamente funciones.

Aquí hay un ejemplo de un “programa” como el que un matemático puede escribir utilizando la notación λ de Church:

fix = λf.(λx.f(λv.x(x)(v)))(λx.f(λv.x(x)(v)))

Lo equivalente en JavaScript sería algo así:

var fix = f => (x => f(v => x(x)(v)))
               (x => f(v => x(x)(v)));

O sea, JavaScript contiene una implementación del cálculo λ que de verdad correo. El cálculo λ está en JavaScript.

Las historias de lo que Alonzo Church y los posteriores investigadores hicieron con el cálculo λ, y como ha sido pasivamente insinuado en casi todos los lenguajes de programación más utilizados están mas allá del análisis de este artículo. Pero si te interesan las fundaciones de la informática, o simplemente quieres ver como un lenguaje con solo funciones puede hacer cosas como ciclos y recursividad, puedes hacer cosas peores que pasar una tarde lluviosa, mirando numerales de Church y combinaciones de punto fijo, y jugar con ellos en tu consola de Firefox, o el Borrador. Con las flechas ES6 además de sus otra fortalezas, JavaScript puede razonablemente llamarse a sí mismo el mejor lenguaje para explorar el cálculo λ.

¿Cuándo puedo usar flechas?

Las funciones flechas ES6, fueron implementadas por mí en Firefox, allá por el 2013. Jan de Mooij las hizo rápidas. Gracias a Tooru Fujisawa y Ziyunfei por algunos parches.

Las funciones flecha también están implementadas en la versión de prueba de Microsoft Edge (el sucesor de Internet Explorer). También están disponibles en Babel, Traceur, y TypeScript, en caso de que te interese usarlos en la Web ahora mismo.

The following two tabs change content below.
Si, mi biografia esta vacia. 🙂

Compartir artículo:

Respuestas populares

  1. Están interesantes estos artículos del nuevo estándar :smiley: se agradece la traducción.

    Leyendo este hay errores en el código unicode de los arrows, no sé si sea solo yo.

    Aparece el =&gt; nada más.

    Saludos.

  2. Si, eso note. parece ser un error de codificación.

  3. Gracias por la nota. Ya hice las correcciones :slight_smile:

Continuar la discusión en foro.mozilla-hispano.org

Participantes

  • ¡Participa!

    Firefox Friends »
    Agrega botones de Firefox en tu sitio web y comparte tu amor por Mozilla Firefox.
    Ayuda a otros usuarios en Twitter.
    Colabora con la comunidad »
    En Mozilla lo importante son las personas. Descubre cómo puedes colaborar.

    Boletín Firefox

    Suscríbete al boletín de novedades de Firefox.

  • Descargas

    Descarga los programas de Mozilla.

    Lo más visto

    cc-by-sa