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:
<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:
erro.message— uma descrição do erroerro.name— o nome do tipo de erro
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:
<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:
<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
- Comente metades: Comente metade do código, veja qual metade tem o problema, e vá reduzindo passo a passo
- console.log em todo lugar: Imprima valores de variáveis em pontos-chave — primitivo, mas eficaz
- Depuração com breakpoints: Mais poderoso que
console.log— pause a execução e modifique variáveis em tempo real - Depuração com pato de borracha: Explique seu código linha por linha para um pato de borracha (ou colega). Frequentemente, você encontra o bug no meio da explicação.
Exemplo: try/catch para Parsing de JSON
<!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>
Exemplo: Erros Personalizados e Validação de Formulário
<!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>
Exemplo: Referência Rápida de Tipos de Erro e Métodos de Console
<!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>
❓ 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 blocotrynunca é alcançado. Porém, se um SyntaxError ocorrer em tempo de execução (ex:JSON.parsefalha, ounew 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 umcatch. Usethrowpara erros,returnpara resultados normais.
📝 Atividades
- 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. - 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> }. - Escreva uma função
tentarNovamente(fn, vezes): executefn, e se lançar erro, tente novamente atévezesvezes. Se todas as tentativas falharem, lance o último erro. Implemente com try...catch.



