Funciones Flecha

Una expresi贸n de funci贸n flecha es una alternativa compacta a una expresi贸n de funci贸n tradicional, pero es limitada y no se puede utilizar en todas las situaciones.

Diferencias y limitaciones:

Comparaci贸n de funciones tradicionales con funciones flecha

Observa, paso a paso, la descomposici贸n de una "funci贸n tradicional" hasta la "funci贸n flecha" m谩s simple:
Nota: Cada paso a lo largo del camino es una "funci贸n flecha" v谩lida

// Funci贸n tradicional
function (a){
  return a + 100;
}

// Desglose de la funci贸n flecha

// 1. Elimina la palabra "function" y coloca la flecha entre el argumento y el corchete de apertura.
(a) => {
  return a + 100;
}

// 2. Quita los corchetes del cuerpo y la palabra "return" 鈥 el return est谩 impl铆cito.
(a) => a + 100;

// 3. Suprime los par茅ntesis de los argumentos
a => a + 100;

Como se muestra arriba, los { corchetes }, ( par茅ntesis ) y "return" son opcionales, pero pueden ser obligatorios.

Por ejemplo, si tienes varios argumentos o ning煤n argumento, deber谩s volver a introducir par茅ntesis alrededor de los argumentos:

// Funci贸n tradicional
function (a, b){
  return a + b + 100;
}

// Funci贸n flecha
(a, b) => a + b + 100;

// Funci贸n tradicional (sin argumentos)
let a = 4;
let b = 2;
function (){
  return a + b + 100;
}

// Funci贸n flecha (sin argumentos)
let a = 4;
let b = 2;
() => a + b + 100;

Del mismo modo, si el cuerpo requiere l铆neas de procesamiento adicionales, deber谩s volver a introducir los corchetes M谩s el "return" (las funciones flecha no adivinan m谩gicamente qu茅 o cu谩ndo quieres "volver"):

// Funci贸n tradicional
function (a, b){
  let chuck = 42;
  return a + b + chuck;
}

// Funci贸n flecha
(a, b) => {
  let chuck = 42;
  return a + b + chuck;
}
Y finalmente, en las funciones con nombre tratamos las expresiones de flecha como variables
// Funci贸n tradicional
function bob (a){
  return a + 100;
}

// Funci贸n flecha
let bob = a => a + 100;

Sintaxis

Sintaxis b谩sica

Un par谩metro. Con una expresi贸n simple no se necesita return:

param => expression

Varios par谩metros requieren par茅ntesis. Con una expresi贸n simple no se necesita return:

(param1, paramN) => expression

Las declaraciones de varias l铆neas requieren corchetes y return:

param => {
  let a = 1;
  return a + b;
}

Varios par谩metros requieren par茅ntesis. Las declaraciones de varias l铆neas requieren corchetes y return:

(param1, paramN) => {
   let a = 1;
   return a + b;
}

Sintaxis avanzada

Para devolver una expresi贸n de objeto literal, se requieren par茅ntesis alrededor de la expresi贸n:

params => ({foo: "a"}) // devuelve el objeto {foo: "a"}

Los par谩metros rest son compatibles:

(a, b, ...r) => expression

Se admiten los par谩metros predeterminados:

(a=400, b=20, c) => expression

Desestructuraci贸n dentro de los par谩metros admitidos:

([a, b] = [10, 20]) => a + b;  // el resultado es 30
({ a, b } = { a: 10, b: 20 }) => a + b; // resultado es 30

Descripci贸n

"this" y funciones flecha

Una de las razones por las que se introdujeron las funciones flecha fue para eliminar complejidades del 谩mbito (this) y hacer que la ejecuci贸n de funciones sea mucho m谩s intuitiva.

Si this es un misterio para ti, consulta este documento para obtener m谩s informaci贸n sobre c贸mo funciona this. Para resumir, this se refiere a la instancia. Las instancias se crean cuando se invoca la palabra clave new. De lo contrario, this se establecer谩 鈥攄e forma predeterminada鈥 en el 谩mbito o alcance de window.

En las funciones tradicionales de manera predeterminada this est谩 en el 谩mbito de window:

window.age = 10; // <-- 驴me notas?
function Person() {
  this.age = 42; // <-- 驴me notas?
  setTimeout(function () {// <-- La funci贸n tradicional se est谩 ejecutando en el 谩mbito de window
    console.log("this.age", this.age); // genera "10" porque la funci贸n se ejecuta en el 谩mbito de window
  }, 100);
}

var p = new Person();

Las funciones flecha no predeterminan this al 谩mbito o alcance de window, m谩s bien se ejecutan en el 谩mbito o alcance en que se crean:

window.age = 10; // <-- 驴me notas?
function Person() {
  this.age = 42; // <-- 驴me notas?
  setTimeout(() => {// <-- Funci贸n flecha ejecut谩ndose en el 谩mbito de "p" (una instancia de Person)
    console.log("this.age", this.age); // genera "42" porque la funci贸n se ejecuta en el 谩mbito de Person
  }, 100);
}

var p = new Person();

En el ejemplo anterior, la funci贸n flecha no tiene su propio this. Se utiliza el valor this del 谩mbito l茅xico adjunto; las funciones flecha siguen las reglas normales de b煤squeda de variables. Entonces, mientras busca this que no est谩 presente en el 谩mbito actual, una funci贸n flecha termina encontrando el this de su 谩mbito adjunto.

Relaci贸n con el modo estricto

Dado que this proviene del contexto l茅xico circundante, en el modo estricto se ignoran las reglas con respecto a this.

var f = () => {
    'use strict';
    return this;
};

f() === window; // o el objeto global

Todas las dem谩s reglas del modo estricto se aplican normalmente.

Nota: Comprueba las notas sobre el modo estricto.

Funciones flecha utilizadas como m茅todos

Como se indic贸 anteriormente, las expresiones de funci贸n flecha son m谩s adecuadas para funciones que no son m茅todos. Observa qu茅 sucede cuando intentas usarlas como m茅todos:

'use strict';

var obj = { // no crea un nuevo 谩mbito
  i: 10,
  b: () => console.log(this.i, this),
  c: function() {
    console.log(this.i, this);
  }
}

obj.b(); // imprime indefinido, Window {...} (o el objeto global)
obj.c(); // imprime 10, Object {...}

Las funciones flecha no tienen su propio this. Otro ejemplo que involucra Object.defineProperty():

'use strict';

var obj = {
  a: 10
};

Object.defineProperty(obj, 'b', {
  get: () => {
    console.log(this.a, typeof this.a, this); // indefinida 'undefined' Window {...} (o el objeto global)
    return this.a + 10; // representa el objeto global 'Window', por lo tanto 'this.a' devuelve 'undefined'
  }
});

call, apply y bind

Los m茅todos call, apply y bind NO son adecuados para las funciones flecha, ya que fueron dise帽ados para permitir que los m茅todos se ejecuten dentro de diferentes 谩mbitos, porque las funciones flecha establecen "this" seg煤n el 谩mbito dentro del cual se define la funci贸n flecha.

Por ejemplo, call, apply y bind funcionan como se esperaba con las funciones tradicionales, porque establecen el 谩mbito para cada uno de los m茅todos:

// ----------------------
// Ejemplo tradicional
// ----------------------
// Un objeto simplista con su propio "this".
var obj = {
    num: 100
}

// Establece "num" en window para mostrar c贸mo NO se usa.
window.num = 2020; // 隆Ay!

// Una funci贸n tradicional simple para operar en "this"
var add = function (a, b, c) {
  return this.num + a + b + c;
}

// call
var result = add.call(obj, 1, 2, 3) // establece el 谩mbito como "obj"
console.log(result) // resultado 106

// apply
const arr = [1, 2, 3]
var result = add.apply(obj, arr) // establece el 谩mbito como "obj"
console.log(result) // resultado 106

// bind
var result = add.bind(obj) // estable el 谩mbito como "obj"
console.log(result(1, 2, 3)) // resultado 106

Con las funciones flecha, dado que la funci贸n add esencialmente se crea en el 谩mbito del window (global), asumir谩 que this es window.

// ----------------------
// Ejemplo de flecha
// ----------------------

// Un objeto simplista con su propio "this".
var obj = {
    num: 100
}

// Establecer "num" en window para mostrar c贸mo se recoge.
window.num = 2020; // 隆Ay!

// Funci贸n flecha
var add = (a, b, c) => this.num + a + b + c;

// call
console.log(add.call(obj, 1, 2, 3)) // resultado 2026

// apply
const arr = [1, 2, 3]
console.log(add.apply(obj, arr)) // resultado 2026

// bind
const bound = add.bind(obj)
console.log(bound(1, 2, 3)) // resultado 2026

Quiz谩s el mayor beneficio de usar las funciones flecha es con los m茅todos a nivel del DOM (setTimeout, setInterval, addEventListener) que generalmente requieren alg煤n tipo de cierre, llamada, aplicaci贸n o vinculaci贸n para garantizar que la funci贸n se ejecute en el 谩mbito adecuado.

Ejemplo tradicional:

var obj = {
    count : 10,
    doSomethingLater : function (){
        setTimeout(function(){ // la funci贸n se ejecuta en el 谩mbito de window
            this.count++;
            console.log(this.count);
        }, 300);
    }
}

obj.doSomethingLater(); // la consola imprime "NaN", porque la propiedad "count" no est谩 en el 谩mbito de window.

Ejemplo de flecha:

var obj = {
    count : 10,
    doSomethingLater : function(){  // por supuesto, las funciones flecha no son adecuadas para m茅todos
        setTimeout( () => { // dado que la funci贸n flecha se cre贸 dentro del "obj", asume el "this" del objeto
            this.count++;
            console.log(this.count);
        }, 300);
    }
}

obj.doSomethingLater();

Sin enlace de arguments

Las funciones flecha no tienen su propio objeto arguments. Por tanto, en este ejemplo, arguments simplemente es una referencia a los argumentos del 谩mbito adjunto:

var arguments = [1, 2, 3];
var arr = () => arguments[0];

arr(); // 1

function foo(n) {
  var f = () => arguments[0] + n; // Los argumentos impl铆citos de foo son vinculantes. arguments[0] es n
  return f();
}

foo(3); // 6

En la mayor铆a de los casos, usar par谩metros rest es una buena alternativa a usar un objeto arguments.

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

foo(1); // 11

Uso del operador new

Las funciones flecha no se pueden usar como constructores y arrojar谩n un error cuando se usen con new.

var Foo = () => {};
var foo = new Foo(); // TypeError: Foo no es un constructor

Uso de la propiedad prototype

Las funciones flecha no tienen una propiedad prototype.

var Foo = () => {};
console.log(Foo.prototype); // undefined

Uso de la palabra clave yield

La palabra clave yield no se puede utilizar en el cuerpo de una funci贸n flecha (excepto cuando est谩 permitido dentro de las funciones anidadas dentro de ella). Como consecuencia, las funciones flecha no se pueden utilizar como generadores.

Cuerpo de funci贸n

Las funciones flecha pueden tener un "cuerpo conciso" o el "cuerpo de bloque" habitual.

En un cuerpo conciso, solo se especifica una expresi贸n, que se convierte en el valor de retorno impl铆cito. En el cuerpo de un bloque, debes utilizar una instrucci贸n return expl铆cita.

var func = x => x * x;
// sintaxis de cuerpo conciso, "return" impl铆cito

var func = (x, y) => { return x + y; };
// con cuerpo de bloque, se necesita un "return" expl铆cito

Devolver objetos literales

Ten en cuenta que devolver objetos literales utilizando la sintaxis de cuerpo conciso params => {object: literal} no funcionar谩 como se esperaba.

var func = () => { foo: 1 };
// 隆Llamar a func() devuelve undefined!

var func = () => { foo: function() {} };
// SyntaxError: la declaraci贸n function requiere un nombre

Esto se debe a que el c贸digo entre llaves ({}) se procesa como una secuencia de declaraciones (es decir, foo se trata como una etiqueta, no como una clave en un objeto literal).

Debes envolver el objeto literal entre par茅ntesis:

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

Saltos de l铆nea

Una funci贸n flecha no puede contener un salto de l铆nea entre sus par谩metros y su flecha.

var func = (a, b, c)
  => 1;
// SyntaxError: expresi贸n esperada, obtuve '=>'

Sin embargo, esto se puede modificar colocando el salto de l铆nea despu茅s de la flecha o usando par茅ntesis/llaves como se ve a continuaci贸n para garantizar que el c贸digo se mantenga bonito y esponjoso. Tambi茅n puedes poner saltos de l铆nea entre argumentos.

var func = (a, b, c) =>
  1;

var func = (a, b, c) => (
  1
);

var func = (a, b, c) => {
  return 1
};

var func = (
  a,
  b,
  c
) => 1;

// no se lanza SyntaxError

Orden de procesamiento

Aunque la flecha en una funci贸n flecha no es un operador, las funciones flecha tienen reglas de procesamiento especiales que interact煤an de manera diferente con prioridad de operadores en comparaci贸n con las funciones regulares.

let callback;

callback = callback || function() {}; // ok

callback = callback || () => {};
// SyntaxError: argumentos de funci贸n flecha no v谩lidos

callback = callback || (() => {});    // bien

Ejemplos

Uso b谩sico

// Una funci贸n flecha vac铆a devuelve undefinided
let empty = () => {};

(() => 'foobar')();
// Devuelve "foobar"
// (esta es una expresi贸n de funci贸n invocada inmediatamente)

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

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

// F谩cil filtrado de arreglos, mapeo, ...

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]

// Cadenas de promesas m谩s concisas
promise.then(a => {
  // ...
}).then(b => {
  // ...
});

// Funciones flecha sin par谩metros que son visualmente m谩s f谩ciles de procesar
setTimeout( () => {
  console.log('suceder谩 antes');
  setTimeout( () => {
    // c贸digo m谩s profundo
    console.log ('Suceder谩 m谩s tarde');
  }, 1);
}, 1);

Especificaciones

Compatibilidad del navegador

BCD tables only load in the browser

Ve tambi茅n