Funções em JavaScript: guia completo para iniciantes
javascript

Funções em JavaScript: guia completo para iniciantes

Fala, dev! Bora aprender sobre funções em JavaScript? Se você está começando a explorar esse universo incrível da programação, já deve ter ouvido falar sobre funções. Elas são como superpoderes do código: permitem organizar, reutilizar e tornar tudo mais eficiente. Neste artigo, vou te mostrar o passo a passo de como criar e utilizar funções no JavaScript de forma prática e descomplicada. E aí, bora codar?

O que são funções?

Funções em JavaScript são blocos de código que realizam uma tarefa específica. Elas são como robôs programados para realizar ações. Você cria a função uma vez e depois pode chamá-la sempre que precisar. Isso torna o código mais organizado, além de evitar repetição desnecessária.
📽️
Assista ao vídeo abaixo. Ele oferece uma base sólida para iniciantes.
Video preview

Exemplo básico de uma função

Vamos começar criando uma função bem simples que imprime uma saudação:
function saudacao() { console.log('Olá, dev! Bem-vindo ao mundo do JavaScript!'); }
Agora, sempre que você quiser ver essa mensagem, basta chamar a função:
saudacao(); // Saída: Olá, dev! Bem-vindo ao mundo do JavaScript!
Simples, né? Você define o que a função faz e depois pode usá-la quantas vezes quiser.

📽️
Precisa revisar os conceitos básicos antes de avançar? Confira o vídeo abaixo! É uma ótima maneira de refrescar a memória e garantir que você está pronto para mergulhar nas funções!
Video preview

Criando funções no JavaScript

Existem diferentes formas de criar funções em JavaScript, e cada uma tem suas particularidades. Se esses conceitos estão parecendo confusos à primeira vista, não se preocupe! É super normal achar tudo isso um pouco complicado no começo. Mas, com a prática e o tempo, essas ideias vão se tornar cada vez mais naturais. O importante é continuar praticando, errar faz parte do processo.

Declaração de função

A forma mais comum de criar uma função é usando a palavra-chave function:
function somar(a, b) { return a + b; }
Aqui, somar é o nome da função, a e b são os parâmetros (valores que a função vai receber) e return devolve o resultado da soma. Para chamar a função e ver o resultado, basta fazer:
console.log(somar(2, 3)); // Saída: 5
console.log?
O console.log é uma ferramenta muito útil para visualizar o que está acontecendo no seu código. Ele imprime no console do navegador (ou terminal, no caso de Node.js) o que você pedir. Nesse exemplo, ele exibe o resultado da função somar(2, 3) no console, que é 5. Isso ajuda bastante a testar e depurar seu código enquanto você desenvolve!

Funções anônimas

Outra maneira de criar funções é utilizando funções anônimas. Elas são chamadas assim porque, diferente das funções tradicionais, não têm um nome específico. Em vez disso, são atribuídas a uma variável, o que permite chamá-las quando necessário.
const multiplicar = function(a, b) { return a * b; };
Aqui, a função foi atribuída à variável multiplicar. Para chamar essa função, você usa o nome da variável, como faria com qualquer outra função:
console.log(multiplicar(2, 4)); // Saída: 8
Funções anônimas são muito úteis quando você precisa passar uma função como argumento para outra função (como em callbacks) ou criar uma função rapidamente, sem se preocupar em nomeá-la. Elas são bastante comuns em situações onde o foco está mais na ação que a função executa do que no nome que ela tem.
Ao trabalhar com funções anônimas, você pode facilmente criar lógica dinâmica e flexível dentro do seu código, tornando o desenvolvimento mais fluido.
Callbacks?
Callbacks são funções que são passadas como argumento para outra função e executadas depois que algum processo é concluído. Em outras palavras, elas permitem que você defina uma função para ser chamada no futuro, após o término de uma operação.

Arrow functions

As arrow functions foram introduzidas no ES6 como uma maneira mais curta e simples de escrever funções. Elas eliminam a necessidade da palavra-chave function e têm uma sintaxe mais enxuta:
const dividir = (a, b) => a / b;
Além da sintaxe curta, uma das principais vantagens é que elas não alteram o valor do this, mantendo o contexto léxico da função onde foi criada. Isso as torna especialmente úteis em callbacks e funções simples:
const numeros = [1, 2, 3, 4]; const dobrados = numeros.map(n => n * 2);
No entanto, como não possuem seu próprio this, elas não são ideais para métodos de objetos que dependem desse contexto.
Contexto léxico, this?
O contexto léxico basicamente significa "onde" uma função foi criada. Ele define o que a função pode acessar em termos de variáveis e objetos. Por exemplo, se você cria uma função dentro de outra, essa função "lembra" do ambiente onde foi criada e pode acessar variáveis daquele escopo.
Agora, o this é uma palavra que usamos para referir ao "dono" da função, ou seja, a quem a função pertence. Em funções normais, o this pode mudar dependendo de como a função é chamada. Isso pode causar confusão, porque o valor de this pode variar.
Com as arrow functions, o valor de this não muda! Ele é "preso" ao contexto onde a função foi criada. Isso significa que, dentro de uma arrow function, o this sempre se refere ao que está fora dela, o que facilita muito o trabalho em certos casos.
Resumindo: o contexto léxico define o que uma função pode acessar, e o this diz "quem" está chamando essa função. As arrow functions mantêm esse this fixo no contexto onde foram criadas, tornando o código mais previsível!

Parâmetros e argumentos

As funções podem receber parâmetros, que são valores passados para a função executar sua tarefa. Por exemplo, uma função que recebe um nome e imprime uma saudação personalizada:
function saudacaoComNome(nome) { console.log(`Olá, ${nome}!`); } saudacaoComNome('Rocketseat'); // Saída: Olá, Rocketseat!
Os argumentos são os valores passados quando chamamos a função, como no exemplo acima, onde o argumento é 'Rocketseat'.

Argumentos padrão

Você também pode definir valores padrão para os parâmetros da função. Se o argumento não for fornecido, a função usa o valor padrão:
function saudacaoComNome(nome = 'dev') { console.log(`Olá, ${nome}!`); } saudacaoComNome(); // Saída: Olá, dev!

Retorno de valores

Funções podem retornar valores usando a palavra-chave return. Isso é útil quando você quer usar o resultado da função em outra parte do código:
function multiplicar(a, b) { return a * b; } const resultado = multiplicar(3, 4); console.log(resultado); // Saída: 12
Se a função não usar return, ela retorna undefined por padrão.

Escopo das funções

Um conceito importante em funções é o escopo, que define onde as variáveis estão disponíveis. As variáveis declaradas dentro de uma função não são acessíveis fora dela:

Escopo local

Variáveis declaradas dentro de uma função não são acessíveis fora dela.
function exemploEscopo() { let mensagem = 'Dentro da função'; console.log(mensagem); } exemploEscopo(); // Saída: Dentro da função console.log(mensagem); // Erro: mensagem não está definida
Se tentar acessar mensagem fora da função, dará erro.

Escopo global

Variáveis declaradas fora de funções são acessíveis em qualquer parte do código.
let mensagemGlobal = 'Fora da função'; function mostrarMensagem() { console.log(mensagemGlobal); } mostrarMensagem(); // Saída: Fora da função

Funções de alta ordem

No JavaScript, as funções são tratadas como "primeira classe", ou seja, podem ser passadas como argumentos ou retornadas por outras funções. Funções que fazem isso são chamadas de funções de alta ordem. Elas são extremamente poderosas, pois permitem criar um código mais flexível e dinâmico.
Um exemplo simples de função de alta ordem é uma função que recebe outra função como argumento:
function executarFuncao(funcao) { funcao(); } executarFuncao(() => { console.log('Função passada como argumento!'); });
Isso é muito útil em várias situações, como em eventos de clique em uma página web, onde você passa uma função que será executada quando o usuário clicar em um botão, ou em operações assíncronas, como carregar dados de uma API.

Callback functions

Um tipo muito comum de função de alta ordem são as callbacks, que são funções passadas como argumentos para outras funções e executadas posteriormente. Elas são amplamente usadas em operações assíncronas, como ao lidar com APIs ou eventos de usuário.
Vamos a um exemplo:
function saudacaoPersonalizada(nome, callback) { const mensagem = `Olá, ${nome}!`; callback(mensagem); } saudacaoPersonalizada('Dev', (msg) => { console.log(msg); });
Nesse caso, a função callback é executada depois que a função saudacaoPersonalizada processa a mensagem, tornando o código mais flexível e modular.

Funções que retornam funções

Além de passar funções como parâmetros, outra caracterísica interessante das funções de alta ordem é que elas podem retornar outras funções. Isso abre portas para muitas possibilidades, como criar funções especializadas dinamicamente.
Veja esse exemplo:
function criarMultiplicador(multiplicador) { return function(numero) { return numero * multiplicador; }; } const dobrar = criarMultiplicador(2); console.log(dobrar(5)); // Saída: 10
Aqui, criarMultiplicador retorna uma função que multiplica um número pelo valor passado inicialmente. É uma maneira poderosa de gerar funções sob demanda, de forma dinâmica e reutilizável.

Funções imediatamente invocadas (IIFE)

As IIFE (Immediately Invoked Function Expressions), ou funções imediatamente invocadas, são funções em JavaScript que são executadas assim que são definidas. Elas são bastante úteis quando você quer criar um escopo isolado para seu código, evitando que variáveis definidas dentro da função "vazem" para o escopo global.
A sintaxe de uma IIFE envolve declarar uma função e, logo em seguida, invocá-la com ():
(function() { console.log('Esta função é executada imediatamente!'); })();
Neste exemplo, a função é definida e imediatamente executada. Isso pode ser útil em vários cenários, como ao encapsular código para não poluir o escopo global, especialmente em projetos grandes ou quando você está lidando com bibliotecas de terceiros.

Por que usar IIFE?

  1. Isolamento de variáveis: as variáveis definidas dentro de uma IIFE não interferem nas variáveis fora dela, ajudando a manter o código mais organizado e livre de conflitos.
  1. Execução imediata: se você precisa executar algum código assim que ele for carregado ou processado (como configurações ou inicializações), a IIFE é uma boa opção.
Exemplo prático:
(function() { let mensagem = 'Este código está isolado!'; console.log(mensagem); })(); console.log(mensagem); // Erro! 'mensagem' não está definida fora da IIFE
Como você pode ver, a variável mensagem existe apenas dentro da IIFE. Se tentarmos acessá-la fora da função, ocorrerá um erro, garantindo que o escopo global permaneça limpo.
As IIFE são um padrão bastante comum em scripts que precisam inicializar algo de imediato ou proteger variáveis do escopo global, especialmente antes do surgimento de módulos no JavaScript.
Embora as IIFE ainda sejam úteis em certos contextos, especialmente ao trabalhar com código legado ou bibliotecas que não utilizam módulos, é importante estar ciente das práticas atuais. Se você estiver iniciando um projeto novo, considere utilizar módulos ES6 para gerenciamento de escopo e organização do código.

Alternativa moderna: módulos ES6

Os módulos ES6 permitem dividir seu código em arquivos separados, cada um com seu próprio escopo. Isso facilita a manutenção e a reutilização de código sem poluir o escopo global. Para importar e exportar funções ou variáveis entre módulos, você pode usar as palavras-chave export e import.
// Em arquivo multiplicar.js export function multiplicar(a, b) { return a * b; } // Em outro arquivo import { multiplicar } from './multiplicar.js'; console.log(multiplicar(2, 4)); // Saída: 8
Dica: usar módulos é a forma recomendada para organizar seu código em projetos modernos de JavaScript.

Recursão

Funções recursivas são aquelas que chamam a si mesmas durante a execução. Elas são úteis para resolver problemas que podem ser divididos em subproblemas menores, como o cálculo de fatorial, percorrer árvores de dados, entre outros. Vamos ver um exemplo clássico de recursão: o cálculo do fatorial de um número.
function fatorial(n) { if (n === 0) { return 1; } return n * fatorial(n - 1); } console.log(fatorial(5)); // Saída: 120

O que está acontecendo no código?

  1. Base da recursão: A função fatorial verifica primeiro se o número n é igual a 0. Se for, ela retorna 1, porque o fatorial de 0 é 1. Essa é a condição de parada, que impede a função de continuar se chamando indefinidamente.
  1. Chamada recursiva: Se n não for 0, a função se chama novamente, passando o valor n - 1. Cada chamada vai multiplicar n pelo fatorial do número anterior até que n seja 0.
  1. Resultado: Para fatorial(5), a sequência é assim:
      • fatorial(5) retorna 5 * fatorial(4)
      • fatorial(4) retorna 4 * fatorial(3)
      • fatorial(3) retorna 3 * fatorial(2)
      • fatorial(2) retorna 2 * fatorial(1)
      • fatorial(1) retorna 1 * fatorial(0)
      • fatorial(0) retorna 1, finalizando a recursão.
  1. Resultado final: Essas multiplicações vão sendo resolvidas de baixo para cima, até que o resultado final, 120, seja retornado e impresso no console.
A recursão permite que problemas complexos sejam resolvidos de forma elegante, mas é importante sempre definir uma condição de parada (como o if (n === 0)) para evitar que a função entre em loop infinito.

Funções assíncronas (Async/Await)

O JavaScript é uma linguagem que lida com muitas operações assíncronas, como requisições de API, leitura de arquivos, ou temporizadores. Anteriormente, usávamos callbacks ou promises para lidar com essas operações. No entanto, com a introdução do async/await no ES8 (ES2017), ficou muito mais fácil escrever e entender código assíncrono de maneira mais parecida com o código síncrono.

O que são funções assíncronas?

Funções assíncronas são funções que permitem o uso da palavra-chave await, tornando o código que lida com promessas (promises) mais limpo e legível. A palavra-chave async marca uma função como assíncrona, enquanto await pausa a execução da função até que a promessa seja resolvida. Essas palavras introduzem uma sintaxe mais simples para lidar com Promises, mas não eliminam a necessidade de entendê-las. Na verdade, toda função assíncrona retorna uma Promise por padrão.
Aqui está um exemplo simples:
async function fetchDados() { try { const resposta = await fetch('https://api.example.com/dados'); const dados = await resposta.json(); console.log(dados); } catch (erro) { console.error('Erro ao buscar dados:', erro); } } fetchDados();

O que está acontecendo no código?

  1. async function: A função fetchDados é marcada como async, o que significa que ela pode conter await dentro dela e retornará uma promessa.
  1. await: O await pausa a execução da função até que a promessa seja resolvida. No primeiro await, a função está esperando que a requisição para 'https://api.example.com/dados' seja concluída. Somente depois que a resposta chega, a execução continua.
  1. Tratamento de erros: O try/catch é usado para lidar com possíveis erros durante a execução do código assíncrono, como problemas de conexão ou respostas inválidas. Se um erro acontecer, ele será capturado no catch, onde podemos tratar o erro de forma adequada.

Benefícios do Async/Await

  • Código mais legível: Com o uso de async/await, o código assíncrono se parece mais com o código síncrono, o que o torna mais fácil de entender e manter.
  • Simplificação: Ele elimina a necessidade de aninhar múltiplas promises e callbacks, que podem deixar o código confuso (callback hell).
  • Melhor controle de erro: Usando try/catch, você tem uma maneira clara de lidar com erros em operações assíncronas, sem precisar usar .catch() em cada promessa.
O uso de async/await simplifica muito o trabalho com operações assíncronas, tornando o código mais limpo e fácil de seguir. Em vez de trabalhar diretamente com promises, você pode usar await para esperar pela resolução e tratar o resultado como faria com código síncrono. Essa abordagem é particularmente útil ao lidar com APIs, leitura de arquivos ou qualquer outra operação que leve algum tempo para ser concluída.
Embora o async/await torne o código assíncrono mais legível, as Promises são a base sobre a qual essa sintaxe é construída. Portanto, compreender como as Promises funcionam é essencial para depurar e escrever código assíncrono eficaz.
  • Boas práticas atuais:
    • Manipulação de erros: utilize try...catch para capturar erros em funções assíncronas, garantindo que exceções sejam tratadas adequadamente.
    • Promise.all e Promise.race: continue usando métodos como Promise.all para executar operações assíncronas em paralelo quando apropriado.
    • Evite bloquear o event loop: mesmo com async/await, esteja atento para não escrever código que possa bloquear o event loop, afetando a performance da aplicação.
    • Uso de finally: com o ES2018, o bloco finally foi introduzido para Promises, permitindo executar código após a resolução ou rejeição de uma Promise.
  • Exemplo atualizado:
async function fetchDados() { try { const resposta = await fetch('https://api.example.com/dados'); if (!resposta.ok) { throw new Error('Erro na rede'); } const dados = await resposta.json(); console.log(dados); } catch (erro) { console.error('Erro ao buscar dados:', erro); } finally { console.log('Operação concluída'); } } fetchDados();
O bloco finally é executado independentemente do resultado da Promise, permitindo liberar recursos ou executar ações finais.
Quer se aprofundar mais? Confira a documentação oficial no MDN sobre funções assíncronas (async) e o uso de try...catch para manipular erros em código JavaScript!
📽️
Quer entender melhor os statements no JavaScript de forma prática? Assista ao vídeo abaixo e aprofunde seus conhecimentos!
Video preview

Métodos de objetos

Métodos são funções que são associadas a um objeto. Quando uma função é declarada dentro de um objeto, ela passa a ser chamada de método desse objeto. Um método pode acessar as propriedades do próprio objeto usando a palavra-chave this, que faz referência ao objeto ao qual o método pertence.
Aqui está um exemplo:
const pessoa = { nome: 'João', saudacao() { console.log(`Olá, meu nome é ${this.nome}`); }, }; pessoa.saudacao(); // Saída: Olá, meu nome é João

O que está acontecendo?

  • A função saudacao foi definida dentro do objeto pessoa, tornando-a um método desse objeto.
  • O this dentro da função se refere ao próprio objeto pessoa. Dessa forma, this.nome acessa o valor da propriedade nome do objeto, que é 'João'.
Os métodos são uma forma eficiente de associar comportamentos a objetos e permitem criar funcionalidades reutilizáveis no contexto dos dados que o objeto contém.

Boas práticas para criar funções

Seguir boas práticas ao criar funções ajuda a manter o código mais legível, fácil de manter e menos propenso a erros. Aqui estão algumas dicas essenciais que refletem as práticas atualizadas.
  • Responsabilidade única: cada função deve realizar apenas uma tarefa específica. Isso torna o código mais modular e fácil de entender. Funções com muitas responsabilidades tendem a ser confusas e difíceis de depurar.
  • Nomes significativos: dê nomes que descrevam claramente o que a função faz. Isso facilita a leitura e a manutenção do código. Em vez de calcular, por exemplo, prefira algo mais descritivo como calcularTotalComDesconto.
  • Evite efeitos colaterais (side effects): funções devem ser previsíveis, ou seja, devem depender apenas dos parâmetros passados e não alterar variáveis externas ou o estado do sistema de forma inesperada. Isso garante que, ao chamar a função, você saiba exatamente o que ela fará.
  • Limite de parâmetros: prefira funções com poucos parâmetros. Idealmente, não mais que três. Se sua função precisa de muitos parâmetros, considere usar um objeto para agrupá-los ou dividir a função em partes menores.
  • Adote a sintaxe moderna: utilize arrow functions e desestruturação de objetos e arrays nos seus códigos para refletir as práticas atuais.
    • // Arrow function com desestruturação const apresentarUsuario = ({ nome, idade }) => { console.log(`Nome: ${nome}, Idade: ${idade}`); }; const usuario = { nome: 'João', idade: 30 }; apresentarUsuario(usuario);
📽️
Quer elevar a qualidade do seu código? Não deixe de assistir ao vídeo e aprenda práticas essenciais para manter seu código organizado e profissional!
Video preview

Aplicações práticas

As funções em JavaScript são extremamente versáteis e podem ser aplicadas de diversas maneiras no desenvolvimento de software. Vamos ver alguns exemplos práticos de como elas podem ser usadas.

Manipulação de arrays

Funções são amplamente utilizadas na manipulação de arrays, especialmente com métodos como .map(), .filter() e .reduce(). Esses métodos permitem transformar, filtrar ou reduzir os arrays usando funções anônimas ou arrow functions.
const numeros = [1, 2, 3, 4, 5]; const quadrados = numeros.map((num) => num * num); console.log(quadrados); // Saída: [1, 4, 9, 16, 25]
A função passada para .map() transforma cada número do array no seu respectivo quadrado. Esse tipo de operação é muito comum quando você precisa transformar ou processar dados em uma lista.

Interação com o DOM

Funções também são essenciais para manipular elementos de uma página web e responder a eventos, como cliques de botões. Nesse caso, é comum usar event listeners para definir o comportamento de um elemento quando o usuário interage com ele.
document.getElementById('meuBotao').addEventListener('click', () => { alert('Botão clicado!'); });
Aqui, uma função anônima é usada para exibir um alerta sempre que o botão é clicado. Isso é muito útil para criar interatividade nas páginas, como validar formulários, exibir mensagens ou até mesmo alterar o conteúdo exibido.
Essas aplicações mostram como o JavaScript, com o poder das funções, é flexível e essencial para manipular dados e criar interatividade na web.
📽️
Interessado em manipulação avançada do DOM? Descubra dicas valiosas no vídeo abaixo e aprimore suas habilidades e torne suas páginas web ainda mais interativas!
Video preview

Conclusão e próximos passos

Funções são essenciais no JavaScript, e dominá-las é um passo importante na sua jornada como dev. Elas tornam seu código mais organizado, reutilizável e eficiente. Agora que você sabe como criar e utilizar funções, que tal colocar em prática e explorar ainda mais?
Se você quer se aprofundar e construir projetos incríveis, a Rocketseat está aqui para te guiar. Na Formação Full Stack, você vai aprender do zero as principais linguagens web, dominar o desenvolvimento full stack e descobrir tudo o que precisa para iniciar sua carreira e conquistar sua primeira vaga em programação. São 13 projetos para o seu portfólio e mais de 40 desafios esperando por você!
🚀
Quer se tornar um desenvolvedor preparado para os desafios no mercado de trabalho? Saiba mais sobre a nossa Formação Full-Stack!

Quer começar do zero? Conheça o Discover!

Se você está começando agora, o Discover da Rocketseat é a escolha ideal. É um curso 100% gratuito que vai te ensinar a programar do zero, de forma prática. Mesmo sem conhecimentos prévios, você vai criar seu primeiro site e descomplicar o código com 5 horas de conteúdo. Ah, e tem certificado no final, viu?
👉
Confira o Discover e dê seus primeiros passos nesse universo da programação: Acesse o Discover aqui!

Participe da maior comunidade dev da América Latina!

A Rocketseat também tem a maior comunidade de desenvolvedores da América Latina, onde milhares de devs compartilham conhecimento e se ajudam todos os dias. Não perca essa chance de se conectar e evoluir junto!
💜
Entre agora no Discord da Rocketseat e participe dessa jornada com outros devs: Acesse a comunidade!

Fique de olho nos canais da Rocketseat

Para não perder nenhuma novidade e se manter atualizado, siga a Rocketseat e seus instrutores nos canais oficiais:

Bora codar e elevar o nível do seu código?

Foi ótimo estar junto com você nessa missão, espero que esse artigo tenha realmente ampliado seus conhecimentos sobre funções no JavaScript! O mais importante é continuar praticando, errando, aprendendo e crescendo. A jornada dev é infinita, e a Rocketseat está sempre aqui para te acompanhar nos próximos desafios. Mal posso esperar para te ver nas próximas missões!
Quer ver mais artigos incríveis que podem ajudar você a dominar ainda mais JavaScript? Dá uma olhada nesses conteúdos que preparamos com carinho para você:
Estamos juntos nessa jornada de aprendizado e evolução contínua. Até a próxima missão, dev!

Aprenda programação do zero e DE GRAÇA

No Discover você vai descomplicar a programação, aprender a criar seu primeiro site com a mão na massa e iniciar sua transição de carreira.

COMECE A ESTUDAR AGORA