Funciones Flecha

This is a new technology, part of the ECMAScript 2015 (ES6) standard.
This technology's specification has been finalized, but check the compatibility table for usage and implementation status in various browsers.

La expresión de función flecha (también conocida como función flecha gruesa) dispone de una sintaxis más corta comparada con la expresión de función convencional y vincula contextualmente el valor de this. Las Funciones Flecha siempre son anónimas.

Sintaxis

// Sintaxis básica:
(param1, param2, paramN) => { statements }
(param1, param2, paramN) => expression
   // equivalente a:  => { return expression; }

// Los paréntesis son opcionales cuando solo dispone de un argumento:
singleParam => { statements }
singleParam => expression

// Una función sin argumentos requiere paréntesis:
() => { statements }

// Avanzado:
// Incluir entre paréntesis el cuerpo para retornar un objeto literal:
params => ({foo: bar})

// Soporta Parámetros rest
(param1, param2, ...rest) => { statements }

Consulta ejemplos de sintaxis más detallados aquí.

Descripción

Consulta también "ES6 In Depth: Arrow functions" on hacks.mozilla.org.

La inclusión de las Funciones Flecha se vieron influenciadas por dos factores: Sintaxis reducida y 
this contextual.

Funciones reducidas

En algunos patrones funcionales, se agradece disponer de funciones reducidas. Compara:

var a = [
  "Hydrogen",
  "Helium",
  "Lithium",
  "Beryl­lium"
];

var a2 = a.map(function(s){ return s.length });

var a3 = a.map( s => s.length );

this Contextual

Anterior a las funciones flecha, cada nueva función definía su propio valor de this (un nuevo objeto en el caso de un constructor, undefined en llamadas a funciones en modo estricto, el objeto contextual si la función se llama como un "método de un objeto", etc.). Lo cual resultaba molesto cuando se intentaba aplicar programación orientada a objetos.

function Person() { 
   // El constructor Person() define `this` como una instancia de sí mismo.   
   this.age = 0; 
   setInterval(function growUp() { 
      // En modo no estricto, la función growUp() define `this` 
      // como el objeto global, el cual es diferente al objeto `this` 
      // definido por el constructor Person().
      this.age++; 
   }, 1000); 
} 

var p = new Person();

En ECMAScript 3/5, este problema fué corregido asignándosele el valor de this a una variable por fuera de la función interna.

function Person() {
  var self = this; // Algunas personas prefieren `that` en lugar de `self`. 
                   // Escoja cualquiera pero sea consistente.
  self.age = 0;

  setInterval(function growUp() {
    // La función tipo callback apunta a la variable `self` la cual
    // contiene el objeto esperado.
    self.age++;
  }, 1000);
}

Alternativamente, el método bind puede ser utilizado para crear una functión donde podremos asignar this al valor deseado, de está forma podemos pasar this a la función growUp().

Las funciones de flecha capturan el valor de this del contexto actual, por lo tanto el código funciona como se espera.

function Person(){
  this.age = 0;

  setInterval(() => {
    this.age++; // |this| apunta al objeto person
  }, 1000);
}

var p = new Person();

Relación con modo estricto (sctrict mode)

Debido a que this es contextual, las reglas de modo estricto asociadas a este son simplemente ignoradas.

var f = () => {'use strict'; return this};
f() === window; // or the global object

El resto de reglas asociadas a modo estricto aplican de forma normal.

Función de flecha invocada a través de los métodos call y apply

Debido a que en las funciones de flecha el valor de this es asignado de forma predefinida, aunque invocar una función de flecha a través de los métodos call() apply() es posible, su ejecución no tendrá en cuenta la asignación arbitraria de this:

var adder = {
  base : 1,
    
  add : function(a) {
    var f = v => v + this.base;
    return f(a);
  },

  addThruCall: function(a) {
    var f = v => v + this.base;
    var b = {
      base : 2
    };
            
    return f.call(b, a);
  }
};

console.log(adder.add(1));         // Imprime 2 como es esperado
console.log(adder.addThruCall(1)); // También imprime 2 aunque se esperaba 3 

Argumentos contextuales

Las funciones de flecha no exponen un objeto arguments por lo que referenciar arguments.length, arguments[0], arguments[1], etc . resultan en errores de referencia no existente. En este caso, arguments puede hacer referencia a una variable arbitraria:

var arguments = 42;
var arr = () => arguments;

arr(); // 42

function foo() {
  var f = () => arguments[0]; // Referencia al objeto arguments
  return f(2);
}

foo(1); // 1

Las funciones de flecha no tienen su propio objeto arguments, por lo que el  parámetro rest es la alternativa en este caso:

function foo() { 
  var f = (...args) => args[0]; 
  return f(2); 
}

foo(1); // 2

Uso de la expresión yield

La expresión yield no puede ser usada dentro de una función de flecha (excepto dentro de funciones tradicionales anidadas).  Como consecuencia, las funciones de flecha no pueden ser usadas como funciones generadoras.

Retorno de objetos literales

Tenga en cuenta que retornar objetos literales usando la sintáxis simplificada => {propiedad:valor} no funciona como se esperaría:

var func = () => {  foo: 1  };               // Al llamar func() retorna undefined!
var func = () => {  foo: function() {}  };   // Error de sintaxis: SyntaxError: function statement requires a name

Eso es debido a que el código dentro de las llaves ({}) es leído como una secuencia de sentencias (p.ej foo es tratado como una etiqueta  o label y no como una propiedad del objeto literal).

En este caso, recuerde encerrar el objeto literal entre paréntesis:

var func = () => ({ foo: 1 });

Ejemplos

// Una función de flecha vacía retorna undefined
let empty = () => {};

(() => "foobar")() // retorna "foobar" 

var simple = a => a > 15 ? 15 : a; 
simple(16); // 15
simple(10); // 10

let max = (a, b) => a > b ? a : b;

// Métodos de arreglos como filtering, mapping mas sencillos...

var arr = [5, 6, 13, 0, 1, 18, 23];
var sum = arr.reduce((a, b) => a + b);  // 66
var even = arr.filter(v => v % 2 == 0); // [6, 0, 18]
var double = arr.map(v => v * 2);       // [10, 12, 26, 0, 2, 36, 46]

//Encadenamiento de promesas de manera sencilla
promise.then(a => {
  // ...
}).then(b => {
  // ...
});

 

 

 

Especificaciones

Especificación Estado Comentario
ECMAScript 2015 (6th Edition, ECMA-262)
The definition of 'Arrow Function Definitions' in that specification.
Standard Definición inicial.

Compatibilidad en navegadores

Característica Chrome Firefox (Gecko) IE/Edge Opera Safari
Soporte básico 45.0 22.0 (22.0)

Edge 12

32 No support
Característica Android Android Webview Firefox Mobile (Gecko) IE Mobile Opera Mobile Safari Mobile Chrome for Android
Basic support No support 45.0 22.0 (22.0) No support No support No support 45.0

Notas específicas para Firefox

  • Implementaciones iniciales de función flecha activaban automáticamente modo estricto. Esto ha cambiado a partir de Firefox 24 donde el uso de "use strict" es requerido.
  • La función de flecha es semánticamente diferente a la implementada en versiones anteriores de Firefox, la cual no eran estándar Expression Closures estas fueron añadidas en Firefox 3 (detalles: Javascript 1.8), para Expression Closures no asigna this al contexto this actual.
  • Antes de Firefox 39, un salto de línea (\n) era incorrectamente permitido despues de los argumentos de la función de flecha. Esto ha sido corregido para alinearse con la especificación de ES2015, por lo tanto código como () \n => {} arrojará SyntaxError a partir de la versión 39.

Temas relacionados

Etiquetas y colaboradores del documento

 Colaboradores en esta página: oagarcia, davecarter
 Última actualización por: oagarcia,