# 7.7.3 - Funções

## 🧠 Funções Ninja: Conceitos Avançados em JavaScript! 🥷

Você já domina o básico, agora é hora de ir além! Vamos descobrir como funções podem se comportar de formas mais complexas (e super úteis) no JavaScript. Preparado para o próximo nível? ⚔️

***

### 😶 Funções anônimas

São funções **sem nome**. Muito usadas quando você **não precisa reutilizar** a função depois.

```javascript
setTimeout(function() {
  console.log("Executando depois de 2 segundos");
}, 2000);
```

Também podem ser guardadas em variáveis:

```javascript
const digaOi = function() {
  console.log("Oi!");
};
```

***

### 🧩 Funções dentro de funções

Sim, você pode declarar uma função **dentro de outra**!

```javascript
function saudacao(nome) {
  function montarMensagem() {
    return "Olá, " + nome + "!";
  }

  return montarMensagem();
}

console.log(saudacao("Maya")); // Olá, Maya!
```

> 💡 Isso é útil para **organizar tarefas** e **proteger variáveis** do escopo externo.

***

### 🔐 Closures (fechamentos)

Closures são funções **que lembram** do lugar onde foram criadas. Elas "guardam" o escopo mesmo depois que a função externa acabou!

```javascript
function criarContador() {
  let contador = 0;

  return function() {
    contador++;
    return contador;
  };
}

const contar = criarContador();

console.log(contar()); // 1
console.log(contar()); // 2
```

> ⚠️ Muito usado em **funções que precisam guardar estado** entre chamadas.

***

### ⬆️ Hoisting: puxando pra cima

Funções **declaradas com `function nome()`** são “**elevadas**” ao topo do código.

```javascript
mostrarMensagem(); // Funciona!

function mostrarMensagem() {
  console.log("Olá!");
}
```

Mas expressões de função **não são hoisted**:

```javascript
mostrarMensagem(); // ❌ Erro!

const mostrarMensagem = function() {
  console.log("Oi!");
};
```

***

### ⏰ `setTimeout` e `setInterval`

#### ⏱ `setTimeout`: executa **depois de um tempo**

```javascript
setTimeout(() => {
  console.log("Passaram 3 segundos!");
}, 3000);
```

#### ⏳ `setInterval`: executa **repetidamente**

```javascript
setInterval(() => {
  console.log("A cada 2 segundos...");
}, 2000);
```

> ⚠️ Use com cuidado para **evitar loops infinitos** ou sobrecarga.

***

### 📞 Callback: passando funções como argumentos

Funções podem ser passadas como parâmetros para outras funções!

```javascript
function processarTexto(texto, callback) {
  let novoTexto = texto.toUpperCase();
  callback(novoTexto);
}

processarTexto("oi", console.log); // OI
```

> 🔁 Muito usado em animações, interações com o usuário, e código assíncrono.

***

### 🔁 Recursão: quando a função chama ela mesma

```javascript
function contagemRegressiva(n) {
  if (n === 0) {
    console.log("FIM!");
  } else {
    console.log(n);
    contagemRegressiva(n - 1);
  }
}

contagemRegressiva(5);
```

> ⚠️ Use com **condição de parada**, senão o navegador pode travar 😅

***

### 📚 Funções já prontas (pré-definidas)

O JavaScript vem com várias funções embutidas:

| Função          | O que faz                              |
| --------------- | -------------------------------------- |
| `parseInt()`    | Converte string em número inteiro      |
| `parseFloat()`  | Converte string em número com decimais |
| `isNaN()`       | Verifica se algo **não é número**      |
| `setTimeout()`  | Executa depois de um tempo             |
| `setInterval()` | Executa várias vezes com intervalo     |
| `alert()`       | Mostra mensagem na tela                |

***

### 🧱 `Function` constructor: use com cuidado!

Você pode criar funções com `new Function(...)`, mas isso é **raro e perigoso**, porque **executa código como texto** (pode ser inseguro e difícil de debugar).

```javascript
const soma = new Function("a", "b", "return a + b");

console.log(soma(2, 3)); // 5
```

> ⚠️ **Evite em código real!** Só use se **sabe exatamente o que está fazendo**.

***

### 👜 Objeto `arguments`: acesso a todos os argumentos

Mesmo sem declarar parâmetros, você pode usar `arguments` para acessar todos os valores passados:

```javascript
function mostrarTodos() {
  for (let i = 0; i < arguments.length; i++) {
    console.log(arguments[i]);
  }
}

mostrarTodos("A", "B", "C");
```

> 🧠 Hoje em dia, o `...rest` é mais moderno e recomendado. Mas `arguments` ainda aparece em códigos antigos.

***

### ⚖️ Comparando formas de criar funções

| Tipo                     | Exemplo                           | Características                    |
| ------------------------ | --------------------------------- | ---------------------------------- |
| **Declaração**           | `function f() {}`                 | Hoisting, nome obrigatório         |
| **Expressão**            | `const f = function() {}`         | Sem hoisting, função anônima       |
| **Arrow**                | `const f = () => {}`              | Curta, não tem `this` próprio      |
| **Function constructor** | `new Function("x", "return x+1")` | Evite! Executa strings como código |

***

### 🧠 Dicas avançadas pra mandar bem:

* **Use `arrow functions`** para funções pequenas e simples.
* **Use nomes claros** para entender melhor seu próprio código no futuro.
* **Evite recursões profundas** sem motivo — use com moderação.
* **Não abuse de funções dentro de funções**, senão o código pode ficar confuso.
* **Evite o uso de `Function()` e `arguments`** em projetos novos — existem formas mais modernas!

***

### 🧪 Desafio avançado:

1. Crie uma função `repetir` que recebe uma **função de callback** e a **quantidade de vezes** que ela deve ser executada.
2. Teste com um callback que imprime `"Olá"` no console.

```javascript
repetir(() => console.log("Olá"), 3);
// Olá
// Olá
// Olá
```

***

### 🎯 Conclusão

Parabéns! 🎉 Agora você já tem uma visão poderosa do que funções podem fazer no JavaScript. Saber disso te permite **criar, organizar e controlar** tudo no seu código com mais confiança.

> ✨ *“Funções são como ferramentas mágicas: quando você entende cada tipo e como usá-las, o impossível vira possível!”*
