Arrow Functions (ou funções de seta)
Tags: javascript, webdev, beginners, fullstack
Published: 2020-02-26 02:09:40

Oi Pessoas

A nova (nem tão nova) versão de javascript ES6 trouxe as **_arrow functions_**. São uma nova forma de criar funções utilizando setas `() => {}`.

Poderia dizer que **_arrow functions_** substitui as **_functions_**, mas é bem mais que isso, é uma forma com sintaxe mais curta e elegante para criar funções. Além disso, nem sempre elas podem ser usadas.

Neste post, além de explicar a sintaxe, vou explicar as diferenças de escopo.

>IMPORTANTE: Todos os exemplos podem ser executados no console do Navegador, no Chrome, tecle (Ctrl + Shift + J)

>IMPORTANTE: Leia no final deste post onde não devem ser usadas as **_arrow functions_**






#### Sintaxe

A sintaxe para criação de **_arrow functions_** possui 3 partes `() => {}`:
* Os parênteses `()`, que é por onde a função recebe os argumentos (assim como na **_function_** tradicional);
* A seta `=>`, responsável pelo nome “arrow” function;
* E as chaves `{}`, o bloco de código que representa o corpo da função.

>Em algumas situações os parênteses `()` as chaves `{}` são opcionais


Antes, escrito com **_function_** tradicional
```javascript
hello = function() {
  return "Hello World!";
}
hello() // Hello World!
```

Agora escrito em com **_arrow function_**

```javascript
hello = () => {
  return "Hello World!";
}
hello() // Hello World!
```

A princípio não parece muita vantagem, apenas a sintaxe mais curta, a keyword _function_ foi suprimida. Mas podemos deixar mais curta ainda

```javascript
hello = () => "Hello World!";
hello() // Hello World!
```

No exemplo acima, além de suprimir a keyword _function_, também foi suprimida a keyword _return_ e as chaves `{}`






#### Sintaxe com parâmetros

Exemplo de uma função de soma, recebendo dois parâmetros e retornando a soma

Antes, escrito com **_function_** tradicional
```javascript
sum = function (a, b) {
  return a + b
}
sum(10,20) // 30
```

Agora escrito em com **_arrow function_**

```javascript
sum = (a, b) => {
  return a + b
}
sum(10,20) // 30
```

Podemos deixar mais curta ainda

```javascript
sum = (a, b) => a + b
sum(10,20) // 30
```


Se tivermos apenas um parâmetro, podemos escrever sem os parênteses `()`, exemplo:

```javascript
soma10 = a => a + 10
soma10(20) // 30
```







#### Retornar Objetos Literais


As **_arrow functions_** podem ser usadas para retornar uma expressão de objetos literais com uma sintaxe bem mais enxuta _(neste caso, o corpo sempre precisa ser colocado entre parênteses).  


```javascript
//Escrito com function tradicional
var setNameIdsEs5 = function setNameIds(id, name) {
  return {
    id: id,
    name: name
  };
};

//Escrito em com arrow function
var setNameIdsEs6 = (id, name) => ({ id: id, name: name });

console.log(setNameIdsEs6 (4, "Kyle"));   // Object {id: 4, name: "Kyle"}
```




#### Manipulação de array com _map_ ou _reduce_

Um caso comum para **_arrow functions_** é na manipulação de array, é comum que você precise mapear (_map_) ou reduzir (_reduce_) arrays

> Assim que der, vou fazer um post sobre manipulação de arrays

Vamos criar um array simples

```javascript
const smartPhones = [
  { name:'iphone', price:649 },
  { name:'Galaxy S6', price:576 },
  { name:'Galaxy Note 5', price:489 }
];
```

Agora vamos criar uma matriz de objetos com apenas os preços dos smartphones

```javascript
//Escrito com function tradicional
var pricesFunc = smartPhones.map(function(smartPhone) {
  return smartPhone.price;
});

console.log(pricesFunc); // [649, 576, 489]


//Escrito em com arrow function
const pricesArrow = smartPhones.map(smartPhone => smartPhone.price);

console.log(pricesArrow); // [649, 576, 489]
```


Outro exemplo, agora usando o método filter dos arrays


```javascript
const array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];

//Escrito com function tradicional
var divisibleByThrreeES5 = array.filter(function (v){
  return v % 3 === 0;
});

//Escrito em com arrow function
const divisibleByThrreeES6 = array.filter(v => v % 3 === 0);

console.log(divisibleByThrreeES6); // [3, 6, 9, 12, 15]
```

Um exemplo com reduce, neste caso a soma de todos elementos

```javascript
var arr = [5, 6, 13, 0, 1, 18, 23];

var sum = arr.reduce((a, b) => a + b);  
console.log(sum ); // 66
```












#### Promises e Callbacks


Códigos que usam promises e chamadas assincronas (callbacks) geralmente possuem uma grande quantidade de **_function_** e **_return_**

> Assim que der, vou fazer um post sobre __*Promises*__

Se escrevermos com funções modernas, nós atribuímos nossas callbacks às promises retornadas, formando uma cadeia de promise:

```javascript
//Escrito com function tradicional
doSomething().then(function(result) {
  return doSomethingElse(result);
})
.then(function(newResult) {
  return doThirdThing(newResult);
})
.then(function(finalResult) {
  console.log('Got the final result: ' + finalResult);
})
.catch(failureCallback);
```

Os argumentos para `then` são opcionais, e `catch(failureCallback)` é uma abreviação para `then(null, failureCallback)`. 
Agora, escrevendo o mesmo código com **_arrow functions_**:


```javascript
//Escrito em com arrow function
doSomething()
.then(result => doSomethingElse(result))
.then(newResult => doThirdThing(newResult))
.then(finalResult => {
  console.log(`Got the final result: ${finalResult}`);
})
.catch(failureCallback);

```

Particularmente, eu vejo o código em **_arrow functions_** muito mais simples para ler, além de mais elegante.









#### Podemos substituir todas as _function_ por _arrow function_? **NÃO**

Poderíamos pensar que sim, mas não é bem assim, um dos principais motivos é o uso da palavra chave **_this_**.

Tenho um post onde explico sobre **_this_** {% post https://dev.to/kabrau/this-em-javascript-1e2b %}

> Diferente das **_function_** tradicionais, você não consegue *injetar* o **_this_** em **_arrow functions_**. Isso mesmo!

Se o this for usado dentro de uma **_arrow functions_**, esse **_this_** vai fazer referência ao objeto que ele já era referência no momento da criação da **_arrow function_**.



Vamos comparar, se criarmos um objeto com dois métodos, ambos métodos acessam **_this_**, um criado por **_function_** tradicional (correrFunc) e outro por **_arrow function_** (correrArrow).



```javascript
pessoa = {
    nome: "Cebolinha",

    correrFunc: function() {
         console.log(this);
    },

    correrArrow: () => console.log(this)
}
pessoa.correrFunc() // => Object {nome: "Cebolinha", correrFunc:, correrArrow: }
pessoa.correrArrow() // => Window
```

O método correrFunc retorna o próprio objeto e o método correrArrow retorna o objeto window. Isso ocorre porque no momento da criação do objeto, o escopo era do window (mesmo que usasse o _'use strict'_, veja meu post sobre **_this_**).







#### **_Arrow functions_** não tem acesso aos **_arguments_**

Pelo mesmo motivo do **_this_**, **_arrow functions_** não tem acesso aos **_arguments_**, isto é, teria acesso a **_arguments_** globais e não ao contexto local.

```javascript
// Traditional function
var crescente = function() {
  return Array.from(arguments).sort((a, b) => a > b)
}
crescente(3,2,5,1,4,8,7,6); // Array [ 1, 2, 3, 4, 5, 6, 7, 8 ]


// Arrow function
var crescente = () => {
  return Array.from(arguments).sort((a, b) => a > b);
}
crescente(3,2,5,1,4,8,7,6); // Exception: ReferenceError: arguments is not defined
```

Uma solução para usar **_arrow functions_** neste caso seria usar o `spread operator`, para criar uma função com REST params, desta forma

```javascript
// Arrow function com spread operator
var crescente = (...arguments) => {
  return Array.from(arguments).sort((a, b) => a > b);
}
crescente(3,2,5,1,4,8,7,6); // Array [ 1, 2, 3, 4, 5, 6, 7, 8 ]
```








#### **_Arrow functions_** não podem ser usadas como **_constructor_**


As arrow functions não podem ser usadas como construtores, não pode usar o operador `new` para criar uma nova instância de objeto.

```javascript
// Traditional function
const ConstrutorFunc = function () {};
new ConstrutorFunc(); // Object { }

// Arrow function
const ConstrutorArrow = () => {};
new ConstrutorArrow(); // Constructor is not a constructor
```









#### Mais um exemplo de quando NÃO devemos usar  **_arrow functions_**

Outro caso que é bem comum são em eventos, o método `addEventListener` sempre injeta o **_this_**, mas para acessar o **_this_** precisamos usar **_function_** tradicional.

Veja o exemplo:
```javascript
const $input = document.querySelector('input[type="text"]')
$input.addEventListener('input', function () {
  console.log('value:', this.value)
}, false)
```

Assumindo que exista um campo `input`, ao começar a digitar algo dentro desse campo, podemos ver o valor do campo sendo exibido no console, pois o this dentro da função passada como listener do evento é injetado pelo addEventListener, fazendo referência ao objeto do DOM ao qual o evento foi atrelado.

Agora tente usar uma **_arrow functions_** no lugar da **_function_** tradicional 

```javascript
const $input = document.querySelector('input[type="text"]')
$input.addEventListener('input', () => {
  console.log('value:', this.value)
}, false)
```

Nesse caso, veja que o valor exibido no console é sempre **_undefined_** _(a menos que exista um objeto no escopo em que a função foi criada, e esse objeto tenha uma propriedade value)_.






#### Considerações  

* se a função que você tem não depende de `this`, você pode substituir por  **_arrow functions_** sem problemas;

* evite usar o `this`. No caso do exemplo do evento, toda função listener de um evento recebe um objeto de evento, com uma propriedade `target`, que faz referência ao elemento que recebeu o evento. Use esse objeto se precisar manipular ou fazer qualquer coisa com o elemento que disparou o evento, ao invés de usar `this`. Dessa forma você evita os problemas vistos acima;

* **_Arrow functions_** não tem acesso aos **_arguments_** como as **_functions_** tradicionais.

* **_Arrow functions_** não podem ser usadas como **_construtor_**, não podemos aplicar o operador `new`;

* Exceto pelo `this`, `new` e `arguments`, todas as demais **_functions_** tradicionais podem ser trocadas por **_arrow functions_**.








#### Perdi Algo?
Por favor, me diga se eu esqueci de algo!!

Obrigado a [Vinicius Da Mata Pickrodt](https://dev.to/vinipickrodt) pela correção deste post.




#### Referências

<sup>- https://raphaelfabeni.com/es6-arrow-functions/ </sup>
<sup>- https://medium.com/@raphalima8/arrow-functions-declara%C3%A7%C3%A3o-funcionamento-escopos-e-o-valor-de-this-9cb6449bca31</sup>
<sup>- https://blog.da2k.com.br/2019/01/07/javascript-tudo-sobre-arrow-functions/</sup>
<sup>- https://www.sitepoint.com/es6-arrow-functions-new-fat-concise-syntax-javascript/</sup>
<sup>- https://developer.mozilla.org/pt-BR/docs/Web/JavaScript/Reference/Functions/Arrow_functions</sup>
<sup>- https://developer.mozilla.org/pt-BR/docs/Web/JavaScript/Guide/Usando_promises</sup>
<sup>- https://medium.com/@raphalima8/arrow-functions-declara%C3%A7%C3%A3o-funcionamento-escopos-e-o-valor-de-this-9cb6449bca31</sup>
<sup>- https://medium.com/frontend-quest/arrow-functions-vs-functions-9048ec12b5c6</sup>