404 Not Found

404 Not Found


nginx

Erros e Depuração em JavaScript

Escrever código sem bugs é impossível — até o criador do JavaScript produziu o bug typeof null === "object" em apenas 10 dias. Então aprender a encontrar bugs e tratar erros é até mais importante do que aprender a escrever código.

📖 Resumo

Tipos Comuns de Erro

Tipo de Erro Causa Exemplo
SyntaxError Sintaxe inválida if (true { — parênteses desbalanceados
ReferenceError Acessar variável inexistente console.log(naoExiste)
TypeError Operar sobre tipo errado undefined.toString()
RangeError Valor fora da faixa válida new Array(-1)

SyntaxError é capturado antes da execução do código (fase de parsing). Os outros três são erros de execução.

try...catch...finally

Use try...catch para capturar erros de execução e impedir que seu programa trave:

HTML
<script>
try {
  const dados = JSON.parse('{json invalido}');
} catch (erro) {
  console.log("Falha no parsing:", erro.message);
} finally {
  console.log("Trabalho de limpeza");
}
</script>

O objeto erro no catch tem duas propriedades comumente usadas:

throw — Lançando Erros Manualmente

try...catch só pode capturar erros de execução, mas erros de lógica de negócio precisam ser lançados manualmente:

HTML
<script>
function definirIdade(idade) {
  if (typeof idade !== "number" || idade < 0) {
    throw new Error("Idade deve ser um número positivo");
  }
  console.log("Idade definida como: " + idade);
}

try {
  definirIdade(-5);
} catch (e) {
  console.log(e.message);
}
</script>

throw pode lançar qualquer valor, mas usar new Error() ou suas subclasses é recomendado — elas incluem informações de stack trace.

Mensagens de Erro Personalizadas

Use subclasses de Error ou propriedades personalizadas para fornecer informações de erro mais ricas:

HTML
<script>
class ErroValidacao extends Error {
  constructor(campo, mensagem) {
    super(mensagem);
    this.name = "ErroValidacao";
    this.campo = campo;
  }
}

try {
  throw new ErroValidacao("email", "Formato de email inválido");
} catch (e) {
  console.log(e.name + " [" + e.campo + "]: " + e.message);
}
</script>

DevTools do Navegador (F12)

Painel Finalidade
Console Ver logs, executar código, ver erros
Sources Definir breakpoints, percorrer código, inspecionar variáveis
Network Inspecionar requisições de rede, status de resposta, tempos de carregamento
Elements Ver/modificar DOM e estilos

Depuração com breakpoints é a técnica de depuração mais poderosa: clique em um número de linha no painel Sources para definir um breakpoint, atualize a página, e o código pausa naquele ponto — percorra linha por linha, inspecione variáveis e examine a pilha de chamadas.

A Família console

Método Finalidade
console.log() Saída geral
console.warn() Aviso (amarelo)
console.error() Erro (vermelho)
console.table() Exibir arrays/objetos como tabela
console.time() / console.timeEnd() Cronometragem
console.group() / console.groupEnd() Saída agrupada
console.clear() Limpar o console

console.table é especialmente útil para exibir arrays de objetos — muito mais legível que log.

Dicas de Depuração


Exemplo: try/catch para Parsing de JSON

HTML
<!DOCTYPE html>
<html lang="pt-br">
<head>
  <meta charset="UTF-8">
  <title>Parsing de JSON</title>
  <style>
    body { font-family: sans-serif; padding: 20px; }
    .demo { max-width: 600px; margin: 16px auto; }
    textarea { width: 100%; height: 120px; padding: 12px; font-size: 14px; font-family: monospace; border: 2px solid #ccc; border-radius: 6px; resize: vertical; box-sizing: border-box; }
    button { padding: 10px 24px; font-size: 16px; border: none; border-radius: 6px; cursor: pointer; margin: 8px 4px; }
    .parse { background: #4a90d9; color: #fff; }
    .parse:hover { background: #357abd; }
    .bad { background: #d9534f; color: #fff; }
    .bad:hover { background: #c9302c; }
    .result { margin-top: 16px; padding: 16px; border-radius: 8px; }
    .success { background: #d4edda; border: 2px solid #5cb85c; }
    .error-box { background: #f8d7da; border: 2px solid #d9534f; }
    .error-type { font-weight: bold; color: #721c24; }
    .error-msg { margin-top: 4px; color: #721c24; }
  </style>
</head>
<body>
  <h2 style="text-align:center;">Tratamento de Erro no Parse de JSON</h2>
  <div class="demo">
    <textarea id="jsonInput">{
  "nome": "Alice",
  "idade": 20,
  "habilidades": ["JavaScript", "HTML", "CSS"]
}</textarea>
    <div style="text-align:center;">
      <button class="parse" id="parseBtn">Parse JSON</button>
      <button class="bad" id="badBtn">Inserir JSON Inválido</button>
    </div>
    <div id="result"></div>
  </div>
  <script>
    function parseJSON(jsonStr) {
      try {
        const dados = JSON.parse(jsonStr);
        return { sucesso: true, dados: dados };
      } catch (erro) {
        return { sucesso: false, nome: erro.name, mensagem: erro.message };
      }
    }

    document.getElementById("parseBtn").addEventListener("click", function() {
      var entrada = document.getElementById("jsonInput").value;
      var resultado = parseJSON(entrada);
      var saida = document.getElementById("result");

      if (resultado.sucesso) {
        saida.className = "result success";
        saida.innerHTML = "<strong>Parse bem-sucedido!</strong><pre>" +
          JSON.stringify(resultado.dados, null, 2) + "</pre>";
      } else {
        saida.className = "result error-box";
        saida.innerHTML = '<div class="error-type">' + resultado.nome +
          '</div><div class="error-msg">' + resultado.mensagem + '</div>';
      }
    });

    document.getElementById("badBtn").addEventListener("click", function() {
      document.getElementById("jsonInput").value = '{nome: "Alice", idade: 20}';
    });
  </script>
</body>
</html>
▶ Experimente

Exemplo: Erros Personalizados e Validação de Formulário

HTML
<!DOCTYPE html>
<html lang="pt-br">
<head>
  <meta charset="UTF-8">
  <title>Erros Personalizados</title>
  <style>
    body { font-family: sans-serif; padding: 20px; }
    .form { max-width: 440px; margin: 16px auto; padding: 24px; background: #f9f9f9; border-radius: 12px; }
    .row { margin: 12px 0; }
    label { display: block; margin-bottom: 4px; font-weight: bold; }
    input { width: 100%; padding: 10px 12px; font-size: 16px; border: 2px solid #ccc; border-radius: 6px; box-sizing: border-box; }
    input.valid { border-color: #5cb85c; }
    input.invalid { border-color: #d9534f; }
    .field-error { color: #d9534f; font-size: 13px; margin-top: 2px; min-height: 20px; }
    button { padding: 10px 24px; font-size: 16px; border: none; border-radius: 6px; cursor: pointer; background: #4a90d9; color: #fff; width: 100%; margin-top: 8px; }
    button:hover { background: #357abd; }
    .global-msg { margin-top: 12px; padding: 12px; border-radius: 6px; text-align: center; }
    .global-ok { background: #d4edda; color: #155724; }
    .global-fail { background: #f8d7da; color: #721c24; }
  </style>
</head>
<body>
  <h2 style="text-align:center;">Validação com Erros Personalizados</h2>
  <div class="form">
    <div class="row">
      <label>Usuário (3–20 caracteres):</label>
      <input type="text" id="username" placeholder="Digite o usuário" />
      <div class="field-error" id="usernameErr"></div>
    </div>
    <div class="row">
      <label>Idade (0–150):</label>
      <input type="text" id="age" placeholder="Digite a idade" />
      <div class="field-error" id="ageErr"></div>
    </div>
    <div class="row">
      <label>Email:</label>
      <input type="text" id="email" placeholder="Digite o email" />
      <div class="field-error" id="emailErr"></div>
    </div>
    <button id="submitBtn">Enviar</button>
    <div class="global-msg" id="globalMsg"></div>
  </div>
  <script>
    class ErroValidacao extends Error {
      constructor(campo, mensagem) {
        super(mensagem);
        this.name = "ErroValidacao";
        this.campo = campo;
      }
    }

    function validarUsuario(valor) {
      if (!valor.trim()) throw new ErroValidacao("username", "Usuário não pode ficar vazio");
      if (valor.trim().length < 3) throw new ErroValidacao("username", "Usuário deve ter pelo menos 3 caracteres");
      if (valor.trim().length > 20) throw new ErroValidacao("username", "Usuário deve ter no máximo 20 caracteres");
    }

    function validarIdade(valor) {
      if (!valor.trim()) throw new ErroValidacao("age", "Idade não pode ficar vazia");
      var num = Number(valor);
      if (isNaN(num)) throw new ErroValidacao("age", "Digite um número válido");
      if (num < 0 || num > 150) throw new ErroValidacao("age", "Faixa de idade: 0–150");
      if (!Number.isInteger(num)) throw new ErroValidacao("age", "Idade deve ser um inteiro");
    }

    function validarEmail(valor) {
      if (!valor.trim()) throw new ErroValidacao("email", "Email não pode ficar vazio");
      if (!valor.includes("@")) throw new ErroValidacao("email", "Email deve conter @");
      if (!valor.includes(".")) throw new ErroValidacao("email", "Formato de email inválido");
    }

    var validadores = {
      username: validarUsuario,
      age: validarIdade,
      email: validarEmail
    };

    function limparErros() {
      ["username", "age", "email"].forEach(function(campo) {
        document.getElementById(campo).className = "";
        document.getElementById(campo + "Err").textContent = "";
      });
      document.getElementById("globalMsg").innerHTML = "";
      document.getElementById("globalMsg").className = "global-msg";
    }

    document.getElementById("submitBtn").addEventListener("click", function() {
      limparErros();
      var temErro = false;

      ["username", "age", "email"].forEach(function(campo) {
        var valor = document.getElementById(campo).value;
        try {
          validadores[campo](valor);
          document.getElementById(campo).className = "valid";
        } catch (e) {
          temErro = true;
          document.getElementById(campo).className = "invalid";
          document.getElementById(campo + "Err").textContent =
            e.name + ": " + e.message;
        }
      });

      var msg = document.getElementById("globalMsg");
      if (temErro) {
        msg.className = "global-msg global-fail";
        msg.textContent = "Formulário com erros — corrija e tente novamente";
      } else {
        msg.className = "global-msg global-ok";
        msg.textContent = "Todos os campos passaram na validação!";
      }
    });
  </script>
</body>
</html>
▶ Experimente

Exemplo: Referência Rápida de Tipos de Erro e Métodos de Console

HTML
<!DOCTYPE html>
<html lang="pt-br">
<head>
  <meta charset="UTF-8">
  <title>Tipos de Erro & Console</title>
  <style>
    body { font-family: sans-serif; padding: 20px; }
    .section { margin: 20px 0; }
    table { border-collapse: collapse; width: 100%; max-width: 700px; }
    td, th { border: 1px solid #ddd; padding: 10px 14px; text-align: left; }
    th { background: #4a90d9; color: #fff; }
    .trigger { background: #f8d7da; }
    .safe { background: #d4edda; }
    button { padding: 6px 16px; border: none; border-radius: 4px; cursor: pointer; margin: 2px; font-size: 14px; }
    .btn-err { background: #d9534f; color: #fff; }
    .btn-safe { background: #5cb85c; color: #fff; }
    .btn-info { background: #5bc0de; color: #fff; }
    .output { margin-top: 12px; padding: 12px; background: #1a1a2e; color: #e0e0e0; border-radius: 6px; font-family: monospace; font-size: 13px; min-height: 60px; max-height: 200px; overflow-y: auto; }
    .log-line { margin: 2px 0; }
    .log-warn { color: #f0ad4e; }
    .log-error { color: #d9534f; }
    .log-info { color: #5bc0de; }
  </style>
</head>
<body>
  <h2>Demo de Tipos de Erro & Métodos de Console</h2>

  <div class="section">
    <h3>Tipos Comuns de Erro</h3>
    <table>
      <tr><th>Tipo de Erro</th><th>Código Disparador</th><th>Resultado do try/catch</th></tr>
      <tr class="trigger"><td>SyntaxError</td><td><code>JSON.parse("{bad")</code></td><td id="r1"></td></tr>
      <tr class="trigger"><td>ReferenceError</td><td><code>notExistVar</code></td><td id="r2"></td></tr>
      <tr class="trigger"><td>TypeError</td><td><code>undefined.toString()</code></td><td id="r3"></td></tr>
      <tr class="trigger"><td>RangeError</td><td><code>new Array(-1)</code></td><td id="r4"></td></tr>
    </table>
  </div>

  <div class="section">
    <h3>Métodos de Console (Saída Simulada)</h3>
    <button class="btn-info" onclick="simLog('log', 'Log comum')">console.log</button>
    <button class="btn-info" onclick="simLog('warn', 'Mensagem de aviso')">console.warn</button>
    <button class="btn-err" onclick="simLog('error', 'Mensagem de erro')">console.error</button>
    <button class="btn-info" onclick="simLog('info', 'Mensagem informativa')">console.info</button>
    <button class="btn-safe" onclick="simTable()">console.table</button>
    <button class="btn-safe" onclick="simTime()">console.time</button>
    <button class="btn-info" onclick="limparSim()">Limpar</button>
    <div class="output" id="simConsole"></div>
  </div>

  <script>
    var testes = [
      function() { JSON.parse("{bad"); },
      function() { notExistVar; },
      function() { var x; x.toString(); },
      function() { new Array(-1); }
    ];

    var ids = ["r1", "r2", "r3", "r4"];
    var nomes = ["SyntaxError", "ReferenceError", "TypeError", "RangeError"];

    testes.forEach(function(fn, i) {
      try {
        fn();
        document.getElementById(ids[i]).textContent = "Não disparado (inesperado)";
      } catch (e) {
        document.getElementById(ids[i]).innerHTML =
          '<span class="safe">' + e.name + ": " + e.message + '</span>';
      }
    });

    function simLog(tipo, msg) {
      var cls = tipo === "warn" ? "log-warn" :
                tipo === "error" ? "log-error" : "log-info";
      var prefixo = tipo === "warn" ? "⚠" :
                   tipo === "error" ? "✖" : "ℹ";
      adicionarLinha(prefixo + " " + msg, cls);
      if (tipo !== "error") {
        console[tipo](msg);
      }
    }

    function simTable() {
      var dados = [
        { nome: "Alice", idade: 20, nota: 90 },
        { nome: "Bob", idade: 22, nota: 85 },
        { nome: "Charlie", idade: 21, nota: 95 }
      ];
      adicionarLinha("console.table:", "log-info");
      dados.forEach(function(d) {
        adicionarLinha("  " + d.nome + " | " + d.idade + " | " + d.nota, "log-info");
      });
      console.table(dados);
    }

    function simTime() {
      console.time("demo");
      var soma = 0;
      for (var i = 0; i < 1000000; i++) { soma += i; }
      console.timeEnd("demo");
      adicionarLinha("⏱ console.time/timeEnd: 1.000.000 adições concluídas", "log-info");
    }

    function adicionarLinha(texto, cls) {
      var div = document.getElementById("simConsole");
      div.innerHTML += '<div class="log-line ' + (cls || "") + '">' + texto + '</div>';
      div.scrollTop = div.scrollHeight;
    }

    function limparSim() {
      document.getElementById("simConsole").innerHTML = "";
    }
  </script>
</body>
</html>
▶ Experimente

❓ Perguntas Frequentes

P: O try...catch pode capturar SyntaxError? R: Não. SyntaxError é lançado durante a fase de parsing, antes mesmo da execução começar, então o bloco try nunca é alcançado. Porém, se um SyntaxError ocorrer em tempo de execução (ex: JSON.parse falha, ou new Function("sintaxe errada")), ele pode ser capturado.

P: Quando devo usar finally? R: Quando você precisa que operações de limpeza executem independentemente de ter ocorrido um erro — fechar arquivos, liberar recursos, esconder estados de carregamento. Para a maioria dos cenários simples, apenas catch é suficiente.

P: Qual a diferença entre throw e return? R: return é para fluxo normal — quem chama trata o valor retornado. throw é para fluxo anormal — ele pula o código subsequente e sobe na pilha de chamadas procurando um catch. Use throw para erros, return para resultados normais.


📝 Atividades

  1. Escreva uma função divisaoSegura(a, b) que use try...catch para tratar divisão por zero (dica: dividir por zero em JS não lança erro — você precisa verificar e lançar você mesmo). Retorne o resultado ou uma mensagem de erro.
  2. Escreva uma função parseJSONSeguro(str) que faça parsing de uma string JSON. Em caso de falha, retorne { sucesso: false, erro: <mensagem de erro> }. Em caso de sucesso, retorne { sucesso: true, dados: <resultado do parsing> }.
  3. Escreva uma função tentarNovamente(fn, vezes): execute fn, e se lançar erro, tente novamente até vezes vezes. Se todas as tentativas falharem, lance o último erro. Implemente com try...catch.
100%