404 Not Found

404 Not Found


nginx

Métodos Utilitários em JavaScript

Já vimos as conversões de tipos — agora vamos aprender um lote de métodos utilitários que você vai usar no dia a dia. Pense neles como uma faca suíça — cada um é simples, mas vai fazer falta quando precisar.

📖 Resumo

parseInt e parseFloat

Fazem parsing de números a partir do início de uma string, parando no primeiro caractere não numérico:

HTML
<script>
console.log(parseInt("42px"));      // 42
console.log(parseInt("3.14"));      // 3 (apenas parte inteira)
console.log(parseFloat("3.14"));    // 3.14
console.log(parseFloat("3.14abc")); // 3.14
console.log(parseInt("abc42"));     // NaN (não começa com número)
</script>

O segundo argumento de parseInt especifica a base numérica:

HTML
<script>
console.log(parseInt("FF", 16));  // 255 (hexadecimal)
console.log(parseInt("10", 2));   // 2 (binário)
</script>

Armadilha: Sem a base, strings começando com 0x são interpretadas como hexadecimal. Sempre passe 10 como segundo argumento.

isNaN vs Number.isNaN

Método Comportamento
isNaN(valor) Converte para número primeiro, depois verifica se é NaN
Number.isNaN(valor) Verifica estritamente se o valor é NaN (sem conversão)
HTML
<script>
console.log(isNaN("hello"));         // true (Number("hello") → NaN, depois true)
console.log(Number.isNaN("hello"));  // false ("hello" em si não é NaN)
console.log(isNaN(undefined));       // true
console.log(Number.isNaN(undefined));// false
</script>

Conclusão: Use Number.isNaN() — ele não converte tipos silenciosamente.

toFixed

Controla casas decimais, retorna uma string:

HTML
<script>
console.log((3.14159).toFixed(2));  // "3.14"
console.log((3.1).toFixed(4));      // "3.1000" (preenchido com zeros)
console.log((3.145).toFixed(2));    // "3.14" ou "3.15" (problema de precisão de ponto flutuante, arredondamento não garantido)
</script>

Note que toFixed retorna uma string — use Number() para converter de volta para cálculos.

toString

Converte um número para string, com suporte opcional a base numérica:

HTML
<script>
console.log((255).toString());      // "255"
console.log((255).toString(16));    // "ff"
console.log((8).toString(2));       // "1000"
console.log((100).toString(8));     // "144"
</script>

Booleanos e arrays também têm toString:

HTML
<script>
console.log(true.toString());       // "true"
console.log([1,2,3].toString());    // "1,2,3"
</script>

Number.isInteger

Verifica se um valor é um inteiro:

HTML
<script>
console.log(Number.isInteger(5));      // true
console.log(Number.isInteger(5.0));    // true (5.0 é apenas 5)
console.log(Number.isInteger(5.5));    // false
console.log(Number.isInteger("5"));    // false (uma string não é um inteiro)
console.log(Number.isInteger(NaN));    // false
</script>

Math.trunc e Math.sign

Math.trunc simplesmente corta a parte decimal (sem arredondar):

HTML
<script>
console.log(Math.trunc(4.9));    // 4
console.log(Math.trunc(-4.9));   // -4
console.log(Math.trunc(4.1));    // 4
</script>

Math.sign retorna o sinal de um número:

HTML
<script>
console.log(Math.sign(5));       // 1
console.log(Math.sign(-5));      // -1
console.log(Math.sign(0));       // 0
console.log(Math.sign(-0));      // -0
console.log(Math.sign(NaN));     // NaN
</script>

Limitações do typeof

typeof geralmente funciona para verificação de tipos, mas há algumas pegadinhas clássicas:

HTML
<script>
console.log(typeof 42);           // "number"  ✅
console.log(typeof "hello");      // "string"  ✅
console.log(typeof true);         // "boolean" ✅
console.log(typeof undefined);    // "undefined" ✅
console.log(typeof null);         // "object"  ❌ Isso é um bug histórico!
console.log(typeof []);           // "object"  ❌ Arrays também são objetos
console.log(typeof {});           // "object"  ✅
console.log(typeof function(){}); // "function" ✅
</script>

typeof null === "object" é um "bug veterano" do JavaScript — existe desde 1995 e nunca pode ser corrigido. Use value === null para verificar null. Use Array.isArray() para verificar arrays.


Exemplo: Calculadora de Preços

HTML
<!DOCTYPE html>
<html lang="pt-br">
<head>
  <meta charset="UTF-8">
  <title>Calculadora de Preços</title>
  <style>
    body { font-family: sans-serif; padding: 20px; }
    .calc { max-width: 440px; margin: 16px auto; padding: 24px; background: #f9f9f9; border-radius: 12px; }
    .row { margin: 12px 0; display: flex; align-items: center; gap: 10px; }
    label { width: 80px; font-weight: bold; }
    input { padding: 8px 12px; font-size: 16px; border: 2px solid #ccc; border-radius: 6px; flex: 1; }
    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; }
    .result { margin-top: 16px; padding: 16px; background: #fff; border-radius: 8px; border: 2px solid #5cb85c; }
    .result div { margin: 4px 0; }
    .total { font-size: 22px; font-weight: bold; color: #d9534f; }
  </style>
</head>
<body>
  <h2 style="text-align:center;">Calculadora de Preços</h2>
  <div class="calc">
    <div class="row">
      <label>Preço Unit.:</label>
      <input type="text" id="price" value="29.90" placeholder="ex: 29.90" />
    </div>
    <div class="row">
      <label>Quantidade:</label>
      <input type="text" id="qty" value="3" placeholder="ex: 3" />
    </div>
    <div class="row">
      <label>Desconto:</label>
      <input type="text" id="discount" value="0.85" placeholder="ex: 0.85 (15% off)" />
    </div>
    <button id="calc">Calcular</button>
    <div class="result" id="result" style="display:none;"></div>
  </div>
  <script>
    document.getElementById("calc").addEventListener("click", function() {
      const precoStr = document.getElementById("price").value.trim();
      const qtdStr = document.getElementById("qty").value.trim();
      const descontoStr = document.getElementById("discount").value.trim();

      const preco = parseFloat(precoStr);
      const qtd = parseInt(qtdStr, 10);
      const desconto = parseFloat(descontoStr);

      if (Number.isNaN(preco) || preco <= 0) {
        alert("Preço unitário inválido! Digite um número positivo.");
        return;
      }
      if (Number.isNaN(qtd) || qtd <= 0 || !Number.isInteger(qtd)) {
        alert("Quantidade inválida! Digite um número inteiro positivo.");
        return;
      }
      if (Number.isNaN(desconto) || desconto <= 0 || desconto > 1) {
        alert("Desconto inválido! Digite um decimal entre 0 e 1.");
        return;
      }

      const subtotal = preco * qtd;
      const total = subtotal * desconto;
      const economia = subtotal - total;

      document.getElementById("result").style.display = "block";
      document.getElementById("result").innerHTML = `
        <div>Preço Unitário: R$${preco.toFixed(2)}</div>
        <div>Quantidade: ${qtd}</div>
        <div>Subtotal: R$${subtotal.toFixed(2)}</div>
        <div>Desconto: ${(desconto * 100).toFixed(0)}% off (-R$${economia.toFixed(2)})</div>
        <div class="total">Total: R$${total.toFixed(2)}</div>
      `;
    });
  </script>
</body>
</html>
▶ Experimente

Exemplo: Ferramenta de Validação de Entrada

HTML
<!DOCTYPE html>
<html lang="pt-br">
<head>
  <meta charset="UTF-8">
  <title>Validação de Entrada</title>
  <style>
    body { font-family: sans-serif; padding: 20px; }
    .demo { max-width: 500px; margin: 16px auto; }
    .row { margin: 12px 0; display: flex; align-items: center; gap: 10px; }
    label { width: 80px; font-weight: bold; }
    input { padding: 8px 12px; font-size: 16px; border: 2px solid #ccc; border-radius: 6px; flex: 1; }
    input.valid { border-color: #5cb85c; background: #f0fff0; }
    input.invalid { border-color: #d9534f; background: #fff0f0; }
    .msg { font-size: 13px; margin-left: 90px; }
    .msg.valid { color: #5cb85c; }
    .msg.invalid { color: #d9534f; }
    .methods { margin-top: 20px; padding: 16px; background: #f5f5f5; border-radius: 8px; }
    .methods div { margin: 4px 0; font-family: monospace; font-size: 14px; }
  </style>
</head>
<body>
  <h2 style="text-align:center;">Demo de Validação de Entrada</h2>
  <div class="demo">
    <div class="row">
      <label>Idade:</label>
      <input type="text" id="age" placeholder="Digite a idade" />
    </div>
    <div class="msg" id="ageMsg"></div>

    <div class="row">
      <label>Telefone:</label>
      <input type="text" id="phone" placeholder="Digite o telefone" />
    </div>
    <div class="msg" id="phoneMsg"></div>

    <div class="row">
      <label>Valor:</label>
      <input type="text" id="amount" placeholder="Digite o valor" />
    </div>
    <div class="msg" id="amountMsg"></div>

    <div class="methods" id="methods"></div>
  </div>
  <script>
    function validarIdade(valor) {
      const num = parseInt(valor, 10);
      if (valor.trim() === "") return { valido: false, msg: "Não pode ficar vazio" };
      if (Number.isNaN(num)) return { valido: false, msg: "Não é um inteiro válido" };
      if (!Number.isInteger(Number(valor))) return { valido: false, msg: "Idade deve ser um inteiro" };
      if (num < 0 || num > 150) return { valido: false, msg: "Faixa de idade: 0–150" };
      return { valido: true, msg: `Válido — você tem ${num} anos` };
    }

    function validarTelefone(valor) {
      const cortado = valor.trim();
      if (cortado === "") return { valido: false, msg: "Não pode ficar vazio" };
      if (!/^\d+$/.test(cortado)) return { valido: false, msg: "Apenas números" };
      if (cortado.length !== 11) return { valido: false, msg: "Telefone deve ter 11 dígitos" };
      return { valido: true, msg: "Formato correto" };
    }

    function validarValor(valor) {
      const num = parseFloat(valor);
      if (valor.trim() === "") return { valido: false, msg: "Não pode ficar vazio" };
      if (Number.isNaN(num)) return { valido: false, msg: "Não é um número válido" };
      if (num <= 0) return { valido: false, msg: "Valor deve ser maior que 0" };
      return { valido: true, msg: `Válido — valor R$${num.toFixed(2)}` };
    }

    function configurarValidacao(inputId, msgId, validador) {
      const input = document.getElementById(inputId);
      const msg = document.getElementById(msgId);
      input.addEventListener("input", function() {
        const resultado = validador(input.value);
        input.className = resultado.valido ? "valid" : "invalid";
        msg.className = "msg " + (resultado.valido ? "valid" : "invalid");
        msg.textContent = resultado.msg;
        atualizarMetodos();
      });
    }

    configurarValidacao("age", "ageMsg", validarIdade);
    configurarValidacao("phone", "phoneMsg", validarTelefone);
    configurarValidacao("amount", "amountMsg", validarValor);

    function atualizarMetodos() {
      const idade = document.getElementById("age").value;
      const telefone = document.getElementById("phone").value;
      const valor = document.getElementById("amount").value;
      document.getElementById("methods").innerHTML = `
        <strong>Resultados dos Métodos Utilitários:</strong>
        <div>parseInt("${idade}", 10) → ${parseInt(idade, 10)}</div>
        <div>Number.isNaN(parseInt("${idade}")) → ${Number.isNaN(parseInt(idade, 10))}</div>
        <div>parseFloat("${valor}") → ${parseFloat(valor)}</div>
        <div>typeof "${telefone}" → "${typeof telefone}"</div>
      `;
    }
  </script>
</body>
</html>
▶ Experimente

Exemplo: typeof e Verificação de Tipos

HTML
<!DOCTYPE html>
<html lang="pt-br">
<head>
  <meta charset="UTF-8">
  <title>Verificação de Tipos com typeof</title>
  <style>
    body { font-family: sans-serif; padding: 20px; }
    table { border-collapse: collapse; margin: 16px 0; width: 100%; max-width: 700px; }
    td, th { border: 1px solid #ddd; padding: 10px 14px; text-align: left; }
    th { background: #4a90d9; color: #fff; }
    .bug { background: #fff0f0; }
    .ok { background: #f0fff0; }
    .tip { background: #fff8e1; padding: 12px; border-radius: 6px; border-left: 4px solid #f0ad4e; margin: 16px 0; max-width: 700px; }
  </style>
</head>
<body>
  <h2>Verificação typeof para Cada Tipo</h2>
  <div id="output"></div>
  <script>
    const valores = [
      [42, "Número"],
      ["hello", "String"],
      [true, "Booleano"],
      [undefined, "undefined"],
      [null, "null ⚠️"],
      [[1,2,3], "Array ⚠️"],
      [{a:1}, "Objeto"],
      [function(){}, "Função"],
      [NaN, "NaN"],
      [Infinity, "Infinity"],
    ];

    const linhas = valores.map(([val, label]) => {
      const tipoResultado = typeof val;
      const ehBug = (val === null && tipoResultado === "object") ||
                    (Array.isArray(val) && tipoResultado === "object");
      const jeitoCerto = val === null ? "value === null" :
                         Array.isArray(val) ? "Array.isArray(value)" :
                         "typeof está correto";
      return `<tr class="${ehBug ? 'bug' : 'ok'}">
        <td>${label}</td>
        <td><code>${JSON.stringify(val)}</code></td>
        <td><code>"${tipoResultado}"</code></td>
        <td>${ehBug ? "❌ Impreciso" : "✅ Correto"}</td>
        <td>${ehBug ? jeitoCerto : "—"}</td>
      </tr>`;
    });

    document.getElementById("output").innerHTML = `
      <table>
        <tr><th>Tipo Esperado</th><th>Valor</th><th>Resultado typeof</th><th>Preciso?</th><th>Abordagem Correta</th></tr>
        ${linhas.join("")}
      </table>
      <div class="tip">
        💡 Lembre de dois casos extremos: <code>typeof null</code> retorna <code>"object"</code> (bug histórico),
        e <code>typeof []</code> também retorna <code>"object"</code> (arrays não são um tipo distinto).
        Use <code>=== null</code> para verificações de null, e <code>Array.isArray()</code> para verificações de array.
      </div>
    `;
  </script>
</body>
</html>
▶ Experimente

❓ Perguntas Frequentes

P: Por que parseInt("08") pode retornar 0? R: Em alguns motores antigos, strings começando com 0 eram interpretadas como octal. "08" é inválido em octal, então retornava 0. Solução: sempre passe o segundo argumento 10 — ou seja, parseInt("08", 10)8.

P: Por que toFixed não garante arredondamento? R: Porque números de ponto flutuante não podem ser representados exatamente em binário. (0.1 + 0.2).toFixed(1) pode dar "0.3" ou não. Para arredondamento preciso, use Math.round(num * 100) / 100 antes de chamar toFixed.

P: Qual a diferença entre parseFloat e Number()? R: parseFloat("42px") retorna 42 (faz parsing do início, para no primeiro caractere não numérico), enquanto Number("42px") retorna NaN (faz parsing da string inteira — qualquer caractere não numérico causa falha). Use parseFloat para extrair números de texto misto; use Number() para validação estrita.


📝 Atividades

  1. Escreva uma função parseNumeroPortugues(str) que faça parsing de strings como "3,5 reais"3.5, "100 pessoas"100, "cerca de 200"200 (usando parseFloat). Trate o caso em que texto puro retorna NaN.
  2. Escreva uma função formatarMoeda(valor) que receba um número e retorne uma string com separador de milhar e duas casas decimais, ex: 1234567.89"1.234.567,89" (dica: use toFixed e toString com métodos de array).
  3. Escreva uma função obterTipo(valor) que complemente as falhas do typeof: retorne null para null, array para arrays, e o resultado do typeof nos demais casos.
100%