Funciones de flecha en JavaScript

F

Introducción

Si es un desarrollador de JavaScript, es posible que sepa que JavaScript se ajusta a la ECMAScript (ES) estándares. Las especificaciones ES6, o ECMAScript 2015, habían introducido algunas de las especificaciones revolucionarias para JavaScript, como funciones de flecha, clases, operadores de descanso y propagación, promesas, let y const, etc.

En este tutorial, nos centraremos en las funciones de Arrow, que es muy confuso e intimidante para los principiantes de JavaScript.

Sintaxis de la función de flecha

Como sabemos, una función ES5 tiene la siguiente sintaxis:

function square(a) {
    return a * a;
}

En ES6, podemos escribir la misma función con solo una línea de código:

let square = (a) => { return a * a; }

Además, si el cuerpo de la función solo tiene una declaración que devuelve, podemos omitir las llaves {} y el return declaración:

let square = (a) => a * a

Además, si la función toma solo un parámetro, incluso podemos omitir las llaves () alrededor:

let square = a => a * a

Por otro lado, si la función no toma ningún parámetro, podemos escribirlo así:

let results = () => { /* ...some statements */ };

Tenemos que escribir menos código con esta sintaxis mientras proporcionamos la misma funcionalidad, lo que puede ayudar a ordenar y simplificar su código.

La ventaja de esta sintaxis es más notable cuando se usa en devoluciones de llamada. Entonces, un fragmento de código detallado y difícil de seguir como este:

function getRepos() {
    return fetch('https://api.github.com/users/Pharos.sh/repos')
      .then((response) => {
          return response.json();
      }).then((response) => {
          return response.data;
      }).then((repos) => {
          return repos.filter((repo) => {
              return repo.created_at > '2019-06-01';
          });
      }).then((repos) => {
          return repos.filter((repo) => {
              return repo.stargazers_count > 1;
          });
      });
}

se puede reducir a lo siguiente, utilizando las funciones de flecha:

function getRepos() {
    return fetch('https://api.github.com/users/Pharos.sh/repos')
      .then(response => response.json())
      .then(response => response.data)
      .then(repos => repos.filter(repo => repo.created_at > '2019-06-01'))
      .then(repos => repos.filter(repo => repo.stargazers_count > 1));
}

Beneficios de las funciones de flecha

Hay dos beneficios principales de usar las funciones de Arrow. Una es que es una sintaxis más corta y, por lo tanto, requiere menos código. El principal beneficio es que elimina los varios puntos de dolor asociados con el this operador.

Sin vinculación de ‘este’ operador

A diferencia de otros lenguajes de programación orientados a objetos, en JavaScript (antes de las funciones de flecha) cada función definía su referencia de this y depende de cómo se haya llamado a la función. Si tiene experiencia con lenguajes de programación modernos como Java, Python, C #, etc., el operador this o self dentro de un método se refiere al objeto que llamó al método y no a cómo se llama a ese método.

Los programadores siempre se quejaron de que usar this es demasiado complicado en JavaScript. Causa una gran confusión en la comunidad de JavaScript y provoca un comportamiento no deseado del código en algunos casos.

Para comprender mejor el beneficio de las funciones de Arrow, primero comprendamos cómo this funciona en ES5.

El operador ‘this’ en ES5

El valor de this está determinada por el contexto de ejecución de una función, que en términos simples significa cómo se llama a una función.

Lo que aumenta la confusión es que cada vez que se llama a la misma función, el contexto de ejecución puede ser diferente.

Intentemos entenderlo con la ayuda de un ejemplo:

function test() {
    console.log(this);
}
test();

La salida de este programa sería la siguiente en una consola de navegador:

Window {...}

Como llamamos test() desde el contexto global, el this palabra clave se refiere al objeto global que es un Window objeto en los navegadores. Cada variable global que creamos se adjunta a este objeto global Window.

Por ejemplo, si ejecuta el siguiente código en una consola de navegador:

let greetings="Hello World!";
console.log(greetings);
console.log(window.greetings)

serás recibido con ‘¡Hola mundo!’ dos veces:

Hello World!
Hello World!

Como podemos ver la variable global greetings se adjunta al objeto global window.

Tomemos un ejemplo diferente con una función constructora:

function Greetings(msg) {
    this.msg = msg;
};

let greetings = Greetings('Hello World!');
console.log(greetings);

Obtendremos el siguiente mensaje en la consola:

undefined

lo cual tiene sentido porque estamos llamando Greetings() en window contexto y como el ejemplo anterior this se refiere al objeto global window y this.msg ha añadido msg propiedad a la window objeto.

Podemos comprobarlo si ejecutamos:

window.msg

Seremos recibidos con:

Hello World!

Pero si usamos el new operador mientras crea el Greetings objeto:

let greetings = new Greetings('Hello World!');
console.log(greetings.msg);

Seremos recibidos con:

Hello World!

Podemos ver el this operador no se refiere a la global window objetar esta vez. Es el new operador que hace esta magia. los new El operador crea un objeto vacío y hace que el this referirse a ese objeto vacío.

Espero que ahora tenga una idea de nuestra declaración anterior.

this depende de cómo se llame a una función.

Tomemos otro ejemplo:

let greetings = {
    msg: 'Hello World!',
    greet: function(){
        console.log(this.msg);
    }
}

greetings.greet();

Si ejecutamos este código en una consola de navegador, nuevamente seremos recibidos con:

Hello World!

Porque piensas this no se refirió a la window objetar esta vez?

Enlace implícito: this La palabra clave está vinculada al objeto antes del punto.

En nuestro ejemplo, se refiere a greetings objeto.

Pero si asignamos la función de referencia greetings.greet a una variable:

let greetRef = greetings.greet;
greetRef();

Seremos recibidos con:

undefined

¿Eso explica algo? ¿ReString haber llamado a una función en un contexto de ventana del ejemplo anterior?

Como estamos llamando greetRef() en un window contexto, en este caso this se refiere a window objeto y sabemos que no tiene ningún msg propiedad.

Tomemos un escenario más complicado de usar una función anónima:

let factory = {
    items: [5, 1, 12],
    double: function(){
        return this.items.map(function(item, index){
            let value = item*2;
            console.log(`${value} is the double of ${this.items[index]}`);
            return value;
        });
    }
};

Si llamamos factory.double() obtendremos el siguiente error:

Uncaught TypeError: Cannot read property '0' of undefined
    at <anonymous>
    at Array.map (<anonymous>)

El error indica que this.items no está definido, lo que significa this dentro de la función anónima map() no se refiere a la factory objeto.

Estas son las razones por las que llamamos a eso el valor de this está determinada por el contexto de ejecución de una función. Hay ejemplos más complicados sobre este punto de dolor que está más allá del alcance de este tutorial.

Hay varias formas de solucionar este problema, como pasar el this contexto o uso bind(). Pero el uso de estas soluciones hace que el código sea complicado e innecesario.

Afortunadamente, en ES6 las funciones de flecha son más predecibles en términos de referencia a this palabra clave.

El operador ‘this’ y las funciones de flecha en ES6

Primero, convierta la función anónima dentro map() a una función de flecha:

let factory = {
    items: [5, 1, 12],
    double: function(){
        return this.items.map((item, index) => {
            let value = item*2;
            console.log(`${value} is the double of ${this.items[index]}`);
            return value;
        });
    }
};

Si llamamos factory.double() seremos recibidos con:

10 is the double of 5
2 is the double of 1
24 is the double of 12
[10, 2, 24]

Como podemos ver el comportamiento de this dentro de una función de flecha es bastante predecible. En funciones de flecha this siempre tomará su valor del exterior. De hecho, la función de flecha ni siquiera tiene this.

Si nos referimos a this en algún lugar de la función de flecha, la búsqueda se realiza exactamente de la misma manera que si fuera una variable regular, en el ámbito externo. También lo llamamos Alcance léxico.

En nuestro ejemplo, this dentro de la función de flecha tiene el mismo valor que la this afuera, es decir, en el método double(). Entonces, this.items en la función de flecha es la misma que this.items en el método double() y es factory.items.

Las funciones de flecha no se pueden llamar con el new operador

Como la función de flecha no tiene this palabra clave, es obvio que no pueden admitir la new operador.

Conclusión

Las funciones de flecha pueden ser confusas para empezar, pero es muy útil hacer que el código se comporte de manera más predecible con el alcance léxico del this palabra clave. También es fácil para los dedos, ya que le permite escribir menos código.

Como desarrollador de JavaScript, debe sentirse cómodo usándolo, ya que se usa ampliamente con diferentes marcos / bibliotecas frontend como React, Angular, etc. Espero que este tutorial pueda ayudarlo a decidir cuándo y cómo implementar las funciones de flecha en su proyectos futuros.

 

About the author

Ramiro de la Vega

Bienvenido a Pharos.sh

Soy Ramiro de la Vega, Estadounidense con raíces Españolas. Empecé a programar hace casi 20 años cuando era muy jovencito.

Espero que en mi web encuentres la inspiración y ayuda que necesitas para adentrarte en el fantástico mundo de la programación y conseguir tus objetivos por difíciles que sean.

Add comment

Sobre mi

Últimos Post

Etiquetas

Esta web utiliza cookies propias para su correcto funcionamiento. Al hacer clic en el botón Aceptar, aceptas el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Más información
Privacidad