Funções e Hoisting
Published: 2021-03-18 22:48:35

Chegamos a mais um post da minha [saga de estudos](https://dev.to/inando85/bem-vindo-de-novo-javascript-1b48) em JavaScript.

No post de hoje irei falar sobre funções.

### Funções

Funções são um dos principais conceitos fundamentais em qualquer linguagem de programação e fazem parte do tipo de dado `object`.

O principal objetivo das funções é permitir que o desenvolvedor crie um bloco de código dentro da função uma única vez, e a utilize quantas vezes forem necessárias, quando e onde quiser.

Vale ressaltar que o ato de usar uma função, pode receber alguns nomes, mas terão o mesmo significado, podemos invocar um função, ou chamar a função.

Existem duas formas de declarar uma função, são conhecidas como: Function Declaration e Function Expression.

#### Function Declaration

Para declararmos usaremos a seguinte sintaxe:

- Palavra chave `function`
- Nome da função
- Abertura e fechamento de parênteses `()`
- Abertura e fechamento do bloco que irá conter o código que será executado quando a função for invocada `{}`

```js
function sayHi () {
  console.log('Hi!')
}
```

Acima criamos a função, que somente nos retorna impresso no console a `string Hi!`, agora no exemplo abaixo, iremos invocar a função, ou seja, iremos executa-la.

```js
sayHi() // Hi!
```

#### Function Expression

Para declararmos usaremos a seguinte sintaxe:

- Criaremos um variável ou constante
- Atribuiremos a ela a palavra reservada `function`
- Abertura e fechamento de parênteses `()`
- Abertura e fechamento do bloco que irá conter o código que será executado quando a função for invocada `{}`

```js
const sayHello = function () {
  console.log('Hello!')
}
```
A invocação se dá da mesma forma que utilizamos na função criada no exemplo de function declaration.

```js
sayHello() // Hello!
```

#### Hoisting

Diante dos exemplos apresentados acima, não existem muitas diferenças entre os dois tipos de criação de funções.

Mas existe um detalhe importante, que faz muita diferença, que chamamos de `hoisting`.

Hoisting, pode ser traduzido como içamento, que é o mesmo que puxar para cima.

Então, quando criamos uma função da forma function declaration, se esta função estiver em qualquer lugar do código, que não seja no topo da página, o JavaScript por baixo dos panos puxa sua função para o topo do arquivo. 

Com isso, se uma function declaration for criada depois de ela ser invocada, não ocorrerá nenhum problema de execução.

```js
sayHi() // Hi!

function sayHi () {
  console.log('Hi!')
}
```

Já nas funções criadas com function expression, isso não acontece. Se uma function expression for invocada acima de sua criação, retornará um erro de execução, e se for invocada após a criação, será executada normalmente.

```js
sayHello() // Cannot access 'sayHello' before initialization

const sayHello = function () {
  console.log('Hello!')
}

sayHello() // Hello!
```


### Argumentos, Parâmetros e Parâmetros Default

Muitas vezes iremos querer passar valores para dentro de nossas funções, para que algo seja feito com eles.

Abaixo irei criar uma função, onde irei passar dois valores para ela, esses valores devem ser interpretados como variáveis locais, que só poderão ser usados, acessados de dentro da função. Essas valores que são passados na criação da função, recebem o nome de **parâmetros**.

```js
const fullName = function (name, lastName) {
  console.log(`Oi, ${name} ${lastName}`)
}
```

Na hora de invocarmos essa função, devemos passar os valores esperados por ela. No caso ela espera receber dois valores, e esses valores são chamados de **argumentos**.

```js
fullName('Tom', 'Hanks') // Oi, Tom Hanks
```

Importante frisar que a ordem dos argumentos passados, deve corresponder a ordem dos parâmetros, ou seja, o primeiro argumento será atribuído ao primeiro parâmetro, e assim por diante.

```js
fullName('Hanks', 'Tom') // Oi, Hanks Tom
```

Se na execução de um função que espera receber algum valor, esse valor (argumento) não for passado, o JavaScript irá injetar o valor `undefined` automaticamente.

```js
fullName() // undefined undefined
```

Para evitarmos este tipo de comportamento, existe a possibilidade de passarmos um valor inicial na criação da função, que chamamos de **parâmetro default**.

No exemplo abaixo, irei criar a função chamada `myFavoriteFood` passando um parâmetro default para o parâmetro `food`.

Se na sua invocação, o argumento não for passado, o valor informado como parâmetro default, será atribuído automaticamente e se o valor for passado por argumento, ele irá sobrescrever o parâmetro default.

```js
const myFavoriteFood = function (food = 'Pizza') {
 console.log(`Minha comida favorita é: ${food}.`)
}

myFavoriteFood() // Minha comida favorita é: Pizza.
myFavoriteFood('Macarrão') // Minha comida favorita é: Macarrão.
```

#### Retornando Valores

Até o momento, nos exemplos acima, somente exemplifiquei funções que exibem algum valor no console, mas nem sempre iremos usar as funções desta forma.

Existirão casos em que iremos querer que a função retorne algum valor para a gente.

Abaixo irei criar uma função que espera receber como parâmetro um number, a função irá pegar o valor passado por argumento na invocação da função e irá retornar esse valor multiplicado por dois.

Esse retorno será informado dentro da função com o uso da palavra chave `return`.

```js
const double = function (number) {
  return number * 2
}

const result = double(3)
console.log(result) // 6

const showResult = function (value) {
 return `O valor é: ${value}`
}

console.log(showResult(result)) // O valor é: 6
```

Portanto, é desta forma que fazemos uma função retornar um valor, para que possamos usa-lo fora da função.

#### Arrow Function

Esta é uma adição do JavaScript moderno, chegou a linguagem junto com o ECMAScript 6 (ES6).

As `arrow functions` tornam a criação de funções mais curta e concisa.

Abaixo irei criar uma função na sintaxe function expression e irei replicar esta função utilizando a sintaxe de `arrow function`.

```js
// Function Expression

const myTeam = function (team) {
 console.log(`Meu time é: ${team}.`)
}

myTeam('Madureira') // Meu time é: Madureira.

// Arrow Function

const myTeam = (team) => {
 console.log(`Meu time é: ${team}`)
}

myTeam('Olaria') // Meu time é: Olaria.
```

A `arrow function` pode ser ainda mais simplificada, quando escrevemos uma função que tem apenas um parâmetro, podemos remover os parênteses `()`.

```js
const myTeam = team => {
 console.log(`Meu time é: ${team}`)
}

myTeam('Olaria') // Meu time é: Olaria.
```

Obs: A remoção dos parênteses é opcional, mas tenha em mente que caso o parâmetro possua um valor default ou sua função não possua parâmetros, os parênteses devem ser mantidos, caso contrário, sua função não irá funcionar.

Outra possibilidade de encurtamento da escrita de uma `arrow function`, é caso o bloco de código dentro da função retorne apenas uma linha, um valor, nesses casos podemos deixar toda a função em uma única linha.

```js
const myName = name => console.log(name)

myName('Fernando') // Fernando

const double = number => number * 2

console.log(double(3)) // 6

// Sem parâmetro

const myWord = () => console.log('MyWord')

myWord() // MyWord

// Com default parâmetro

const myTeam = (team = 'Botafogo') => console.log(`Meu time é: ${team}`)

myTeam() // Meu time é: Botafogo
myTeam('Juventude') // Meu time é: Juventude
```

#### Funções Vs Métodos

Métodos também são funções, mas são funções que estão associadas a outros tipos de dados, como strings por exemplo, já as funções são criadas sem associação alguma.

O que diferencia um método de uma função é a forma como a gente invoca e aonde é declarado.

##### Funções

Para invocarmos uma função, basta chamarmos ela e ao término do nome realizar a abertura e fechamento de parênteses `()`.

```js
const sayHi = () => 'Hi!'

const greet = sayHi()

console.log(greet) // Hi!
```

##### Métodos

Para invocarmos um método, devemos utilizar a anotação de ponto `.`, como exemplo, abaixo usarei o método de strings `toUpperCase()`, que transforma as letras das strings para maiúsculas.

```js
const name = 'Escobar'

const nameInUpperCase = name.toUpperCase()

console.log(nameInUpperCase) // ESCOBAR
```

Vou deixar o link para a documentação da MDN sobre [funções](https://developer.mozilla.org/pt-BR/docs/Web/JavaScript/Reference/Global_Objects/Function)

________________________________________________________________

Esse foi mais um post da minha saga de estudos em JavaScript Vanilla. Espero que estejam gostando!

Qualquer dúvida ou sugestão, vocês me encontram nas minhas redes sociais:

[LinkedIn](https://linkedin.com/in/inando85)
[GIthub](https://github.com/inando85)
[Twitter](https://twitter.com/inando85)