Introdução: Por que JavaScript é um campo minado para iniciantes?
JavaScript é uma linguagem que é ao mesmo tempo simples de aprender e difícil de dominar profundamente. Muitos desenvolvedores iniciantes, ao chegarem no Node.js, se deparam com bugs inesperados que parecem irracionais. O problema muitas vezes não está na lógica do algoritmo, mas em características fundamentais da linguagem: assincronicidade, comportamento não óbvio de this e detalhes dos escopos de variáveis.
Neste artigo, vamos analisar os erros mais comuns que iniciantes cometem em JavaScript (usando Node.js como exemplo). Cada tópico será acompanhado de código real e uma explicação de como corrigi-lo. Se você quer escrever código confiável e não perder horas em debugging, este material é para você.
1. Confusão com escopo de variáveis: var, let e const
Um dos problemas mais frequentes é o uso do obsoleto var e a falta de compreensão da diferença entre let e const.
Problema com var e Hoisting (Elevação)
Variáveis declaradas com var são "elevadas" ao início da função, mas permanecem como undefined até o momento da inicialização. Isso leva a bugs difíceis de rastrear.
// ❌ Erro: undefined em vez de ReferenceErrorconsole.log(myVar); // undefined (sem erro!)var myVar = 5;
// ✅ Correto: let ou constconsole.log(myLet); // ReferenceError: Cannot access 'myLet' before initializationlet myLet = 5;Closures em loops
Erro clássico com var em loops:
// ❌ Incorreto: todos os callbacks exibirão 3for (var i = 0; i < 3; i++) { setTimeout(() => console.log(i), 100);}// Saída: 3, 3, 3
// ✅ Correção: let cria um novo vínculo para cada iteraçãofor (let i = 0; i < 3; i++) { setTimeout(() => console.log(i), 100);}// Saída: 0, 1, 2Dica: Esqueça o var no JavaScript moderno. Use const por padrão e let se a variável precisar ser reatribuída.
2. Inferno Assíncrono: Callback Hell e trabalho incorreto com Promises
Node.js é construído sobre assincronicidade. Iniciantes frequentemente tentam obter o resultado de uma função assíncrona de forma síncrona, o que resulta em undefined.
Ignorando Promises
// ❌ Erro: a função retorna undefinedfunction getUserData(userId) { const user = database.findUser(userId); // Operação assíncrona return user; // undefined, pois os dados ainda não chegaram}
// ✅ Correto: retornamos uma Promiseasync function getUserData(userId) { const user = await database.findUser(userId); return user;}Callback Hell (Inferno dos Callbacks)
Callbacks aninhados tornam o código ilegível e difícil de manter:
// ❌ Ruim: pirâmide de callbacksfs.readFile('a.txt', (err, dataA) => { fs.readFile('b.txt', (err, dataB) => { fs.writeFile('c.txt', dataA + dataB, (err) => { console.log('Pronto!'); }); });});
// ✅ Bom: async/awaitasync function mergeFiles() { const dataA = await fs.promises.readFile('a.txt'); const dataB = await fs.promises.readFile('b.txt'); await fs.promises.writeFile('c.txt', dataA + dataB); console.log('Pronto!');}Regra de ouro: Se você vir aninhamento com mais de 2 níveis, refatore usando async/await.
3. O Misterioso this: perda de contexto
Em JavaScript, this é determinado por como a função é chamada, não onde ela é declarada. Esta é a principal causa de confusão.
Perda de this em métodos de objeto
const user = { name: 'Alex', greet() { console.log(`Olá, ${this.name}`); }};
// ✅ Funcionauser.greet(); // Olá, Alex
// ❌ Erro: this foi perdido