Skip to content
This page has been auto-translated and may contain errors.View in English

Números e matemática

docs.scrimba.com

Um carrinho de compras soma preços, um jogo rastreia uma pontuação, um formulário calcula quanto imposto cobrar. Tudo se resume a números e fazer aritmética com eles. JavaScript trata números como um dos seus blocos de construção principais, e este capítulo é sobre o que você pode fazer com eles: a matemática do dia a dia, os auxiliares integrados para arredondamento e aleatoriedade, e a parte que pega quase todo mundo, transformar texto digitado em uma página de volta em um número que você pode somar.

Números e aritmética

JavaScript tem um tipo number, e ele cobre tudo. Números inteiros como 42 e decimais como 9.99 são o mesmo tipo de valor, então você nunca escolhe entre eles:

js
const price = 9.99;
const quantity = 3;
const total = price * quantity;
console.log(total); // 29.97

Você faz matemática com os símbolos que já conhece: + adiciona, - subtrai, * multiplica, e / divide. Há mais um que é menos familiar, %, o resto. Ele dá o que sobra após dividir:

js
const remainder = 7 % 2;
console.log(remainder); // 1

Sete dividido por dois é três com um deixado, então 7 % 2 é 1. É assim que você verifica se um número é par: um número par dividido por dois não deixa nada, então number % 2 é 0 para números pares e 1 para ímpares.

JavaScript tem um único tipo number para números inteiros e decimais, então 42 e 9.99 são do mesmo tipo de valor. Isso é diferente de linguagens que dividem inteiros e decimais em tipos separados; aqui você nunca declara qual você quer dizer.

Os cinco operadores aritméticos são +, -, *, /, e %. O operador resto % retorna o que sobra após divisão, e ele se mostra mais útil do que iniciantes esperam:

js
const total = 17;
const perRow = 5;
const leftOver = total % perRow;
console.log(leftOver); // 2

Colocar 17 itens 5 por linha deixa 2 na última linha, e 17 % 5 te diz isso. O uso clássico é testar par ou ímpar: count % 2 é 0 para números pares e 1 para ímpares, que é como você alterna cores de linha ou divide uma lista no meio.

Operadores seguem precedência normal de matemática, então *, /, e % se ligam mais forte que + e -, e operadores de igual precedência leem da esquerda para a direita. Use parênteses quando a ordem importa:

js
const withTax = (100 + 20) * 1.1;
console.log(withTax); // 132

JavaScript tem um tipo number, um valor de ponto flutuante de 64 bits (o IEEE 754 double, a mesma representação que a maioria das linguagens chama de double). Não há um tipo inteiro separado neste nível, o que significa 42, 9.99, e -3 são tudo do mesmo tipo, e cada inteiro que você escreve é realmente um float que acontece de não ter uma parte fracionária.

Os cinco operadores são + - * / %. O resto % é o que vale a pena precisar, porque é resto, não módulo: ele toma o sinal do operando esquerdo, então -7 % 3 é -2, não 1. Para o caso do dia a dia seu valor é estável e útil. Testar n % 2 === 0 para par é o truque canônico, e ele funciona para negativos também já que -4 % 2 ainda é 0.

js
const total = 128;
const pageSize = 25;
const onLastPage = total % pageSize;
console.log(onLastPage); // 3

Precedência segue matemática padrão: *, /, e % compartilham um nível acima de + e -, e dentro de um nível a avaliação é da esquerda para a direita (associatividade à esquerda). A gramática inteira é mais em camadas do que isso uma vez que comparações e lógica entram, que é o assunto de operadores. Para aritmética sozinha a regra que você precisa é simples: multiplicativo antes de aditivo, coloque parênteses em qualquer coisa que um leitor teria que pausar. Clareza vence economizar três caracteres.

js
const average = (a + b + c) / 3;
JunoNúmeros e aritmética Há um tipo number em JavaScript, então números inteiros e decimais são a mesma coisa e você nunca escolhe entre eles. Os operadores são + - * / mais %, o resto, que é o que sobra após dividir. O truque prático é % 2: é 0 para números pares e 1 para ímpares.
JunoNúmeros e aritmética Um tipo número cobre números inteiros e decimais, então não há decisão int-versus-float a fazer. Os cinco operadores são + - * / e %, e % vale a pena lembrar: count % 2 te dá par-ou-ímpar, e também te diz o que sobra em uma linha parcialmente preenchida. Precedência é matemática normal, então coloque parênteses em qualquer coisa que um leitor teria que pensar.
JunoNúmeros e aritmética Todo número é um float de 64 bits, então não há um tipo inteiro separado e 42 é um double sem fração. A única pegadinha em % é que é resto, não módulo, então toma o sinal do lado esquerdo e -7 % 3 é -2. Para o teste par-ou-ímpar isso nunca te pega, já que n % 2 === 0 funciona para negativos também.

O objeto Math

Quando você precisa de mais que os operadores básicos, JavaScript te dá Math, uma coleção integrada de auxiliares de matemática. Você as chama pelo nome com um ponto:

js
console.log(Math.round(4.6)); // 5
console.log(Math.floor(4.6)); // 4
console.log(Math.ceil(4.1)); // 5

Math.round arredonda para o número inteiro mais próximo, Math.floor sempre arredonda para baixo, e Math.ceil sempre arredonda para cima. Há também Math.max e Math.min, que escolhem o maior ou o menor dos números que você dá a eles:

js
console.log(Math.max(3, 8, 5)); // 8
console.log(Math.min(3, 8, 5)); // 3

E Math.random, que dá um decimal aleatório de 0 até (mas não incluindo) 1. Por si só isso é raramente o que você quer, então a receita comum é multiplicar por ele e arredondar para baixo para obter um número inteiro aleatório:

js
const roll = Math.floor(Math.random() * 6) + 1;
console.log(roll); // 4 (um número diferente cada vez)

Math.random() * 6 cai em algum lugar de 0 até 6, Math.floor o cai para um número inteiro de 0 a 5, e + 1 o desloca para um lançamento de dado de 1 a 6.

Math é um objeto integrado contendo funções e constantes de matemática. Você não o cria; ele está sempre lá, e você chama seus métodos com um ponto.

O trio de arredondamento é aquele que você mais usa:

js
console.log(Math.round(4.5)); // 5, número inteiro mais próximo
console.log(Math.floor(4.9)); // 4, sempre para baixo
console.log(Math.ceil(4.1)); // 5, sempre para cima

Math.max e Math.min retornam o maior e o menor de seus argumentos, o que é útil para colocar um valor em um intervalo:

js
const clamped = Math.min(Math.max(userValue, 0), 100);
console.log(clamped); // fica entre 0 e 100

Math.random retorna um float no intervalo [0, 1), significando que 0 é possível mas 1 nunca é. Para transformar isso em um número inteiro aleatório de 0 até n, o padrão é Math.floor(Math.random() * n):

js
const index = Math.floor(Math.random() * 5);
console.log(index); // um número inteiro de 0 a 4

Multiplicar estende o intervalo para [0, n), e arredondar para baixo corta o decimal então você cai em um número inteiro. Adicione um deslocamento quando você quer um intervalo que não começa em zero, como + 1 para um lançamento de dado.

Math é um objeto de namespace estático: um simples contêiner de métodos e constantes de matemática, não algo que você instancia. Cada método é chamado como Math.something(), e há exatamente um Math no runtime.

Os métodos de arredondamento cada um arredondam para um alvo diferente: Math.round para o mais próximo (empates vão para cima, então Math.round(2.5) é 3 mas Math.round(-2.5) é -2), Math.floor para o infinito negativo, Math.ceil para o infinito positivo. Essa distinção floor-não-é-truncação importa para negativos, onde Math.floor(-1.2) é -2, não -1.

js
console.log(Math.floor(-1.2)); // -2, floor vai para baixo mesmo para negativos

Math.max e Math.min tomam qualquer quantidade de argumentos e são a maneira limpa de colocar um limite:

js
const clamped = Math.min(Math.max(value, min), max);

Math.random retorna um float distribuído uniformemente em [0, 1). O idioma para um inteiro aleatório é Math.floor(Math.random() * range) + start: escala pela largura do intervalo, arredonda para baixo para um inteiro, desloca pelo início. Duas advertências que valem carregar: não é criptograficamente seguro, então nunca o use para tokens ou qualquer coisa que um usuário não deveria adivinhar (crypto.getRandomValues existe para isso), e bugs off-by-one vêm de confundir limites inclusivos e exclusivos, então decida de frente se seu valor superior é alcançável.

js
const dice = Math.floor(Math.random() * 6) + 1;
console.log(dice); // 1 a 6 inclusive
JunoO objeto MathMath é uma caixa de ferramentas pronta de auxiliares de matemática que você chama com um ponto: Math.round, Math.floor (para baixo), Math.ceil (para cima), e Math.max / Math.min para o maior e o menor. Math.random dá um decimal de 0 até 1, e a receita que vale memorizar é Math.floor(Math.random() * n) para um número inteiro aleatório. Levei algumas tentativas para confiar nesse padrão, então copie e leia lentamente.
JunoO objeto MathMath sempre está lá, nenhuma configuração necessária, e você chama seus métodos com um ponto. Mantenha o trio de arredondamento em linha: round para o mais próximo, floor para baixo, ceil para cima, e use min e max juntos para colocar um valor em um intervalo. Para aleatoriedade, Math.floor(Math.random() * n) dá um número inteiro de 0 até n, e um deslocamento move o intervalo.
JunoO objeto MathMath é um namespace estático, então há um deles e nada a construir. Observe os alvos de arredondamento em negativos: Math.floor(-1.2) é -2, não truncamento, e Math.round quebra empates para cima. Math.floor(Math.random() * range) + start é o idioma inteiro, mas Math.random não é seguro, então use crypto.getRandomValues para qualquer coisa que um usuário não deveria adivinhar.

Transformar strings em números

Qualquer coisa que uma pessoa digita em uma página chega como text, mesmo quando parece um número. Digite 5 em uma caixa e você obtém a string "5", não o número 5. Isso importa porque + em duas strings as une em vez de adicionar:

js
const a = "5";
const b = "3";
console.log(a + b); // "53", não 8

Para fazer matemática, você converte o texto em um número primeiro. A maneira mais clara é Number():

js
const count = Number("5");
console.log(count + 3); // 8

Há duas mais que você verá: parseInt lê um número inteiro e descarta qualquer decimal, e parseFloat mantém o decimal:

js
console.log(parseInt("42px")); // 42
console.log(parseFloat("9.99")); // 9.99

Ambas podem ler um número sentado no início de algum texto, como "42px", que Number não pode. Há também um atalho, um + na frente de uma string, que a converte do mesmo jeito que Number faz:

js
console.log(+"7"); // 7

A entrada de uma página é sempre uma string. Um campo de formulário, uma URL, um atributo de dados: tudo texto, mesmo "5". Já que + concatena strings, adicionar dois valores de texto os une em vez de somá-los, que é o bug de números mais comum para iniciantes:

js
const price = "10";
const shipping = "5";
console.log(price + shipping); // "105", concatenação de string

Converta antes de calcular. Number() é a escolha rigorosa e legível: transforma uma string numérica limpa em um número e dá NaN para qualquer coisa que não seja totalmente numérica.

js
console.log(Number("42")); // 42
console.log(Number("42px")); // NaN, não totalmente numérico

parseInt e parseFloat são mais indulgentes. Eles leem um número da frente de uma string e param no primeiro caractere que não se encaixa, é por isso que parseInt("42px") é 42. parseInt descarta qualquer parte fracionária; parseFloat a mantém:

js
console.log(parseInt("42px", 10)); // 42
console.log(parseFloat("3.14 radianos")); // 3.14

Passe 10 como o segundo argumento para parseInt para que ele sempre leia base dez. O + unário é um conversor terse que se comporta como Number: use Number() para valores inteiros, parseInt/parseFloat para números embutidos em texto.

Texto do mundo externo é sempre uma string, e porque + está sobrecarregado para concatenação, "10" + "5" é "105". Cada operador aritmético exceto + força seus operandos para números, então "10" * 1 é 10, mas contar com isso é uma armadilha de legibilidade. Converta deliberadamente.

Number() é coerção de string inteira: sucede apenas se toda a string aparada é um literal numérico válido, caso contrário NaN. Entende hexadecimal (Number("0x1f") é 31), expoentes, e espaço em branco principal ou final, e trata "" como 0, que é uma borda afiada que vale a pena saber.

js
console.log(Number("")); // 0, uma afiada de se perder
console.log(Number("  12 ")); // 12, espaço em branco aparado
console.log(Number("12abc")); // NaN

parseInt e parseFloat analisam um prefixo: eles leem o máximo que podem e ignoram o resto, então parseInt("12abc") é 12. Sempre dê a parseInt sua raiz (parseInt(str, 10)); sem ela, uma entrada como "0x10" é lida como hexadecimal. O + unário é a forma mais curta de coerção Number e aparece frequentemente em código terse (+"3.5" é 3.5), com as mesmas regras e a mesma surpresa "" vira 0.

A regra prática: Number (ou +) quando o valor inteiro deve ser numérico e qualquer outra coisa é um erro que você quer pegar, parseInt/parseFloat quando um número está embutido em texto que você espera. Seja qual for você escolher, o resultado pode ser NaN, que a próxima seção é sobre. Comparação e coerção além disso vivem em operadores, e o lado string da história está em strings.

JunoTransformar strings em números Qualquer coisa digitada em uma página é texto, então "5" não é o número 5, e "5" + "3""53" em vez de 8. Converta primeiro: Number("5") é o mais claro, parseInt lê um número inteiro, parseFloat mantém decimais, e um + na frente de uma string é um atalho rápido. Observe a armadilha de unir-em-vez-de-adicionar, ela pega todo mundo uma vez.
JunoTransformar strings em números A entrada de página é sempre uma string, e já que + une strings, "10" + "5" é "105", o bug de números mais comum que há. Use Number() quando o valor inteiro deve ser numérico, e parseInt ou parseFloat quando um número está sentado dentro de texto como "42px". Dê a parseInt seu argumento de base dez e ele não o surpreenderá.
JunoTransformar strings em números Todo operador exceto + força para número, então "10" * 1 funciona, mas converta de propósito em vez disso. Number() exige que a string inteira seja numérica e silenciosamente transforma "" em 0, enquanto parseInt e parseFloat analisam um prefixo e ignoram o resto, então sempre passe a parseInt uma raiz de 10. Qualquer um deles pode lhe dar NaN, que é a próxima coisa em que se sentir confortável.

As arestas afiadas dos números

Números em JavaScript têm uma surpresa que vale a pena ver uma vez, cedo. Adicione dois decimais simples e você pode obter uma resposta estranha:

js
console.log(0.1 + 0.2); // 0.30000000000000004

Isso não é um bug no seu código. Computadores armazenam decimais de uma forma que não pode representar cada valor exatamente, então um erro minúsculo se esgueira. Raramente importa, e quando importa, você arredonda o resultado para exibição:

js
const sum = 0.1 + 0.2;
console.log(Math.round(sum * 100) / 100); // 0.3

Você também encontrará um valor chamado NaN, abreviação de "não é um número". Você obtém quando uma operação de matemática não tem resposta sensata, como tentar transformar texto sem sentido em um número:

js
console.log(Number("hello")); // NaN

Ver NaN em sua saída geralmente significa que uma conversão deu errado em algum lugar, então é uma pista útil em vez de algo a temer.

Dois valores de número o surpreenderão eventualmente, e é melhor conhecê-los de propósito.

O primeiro é imprecisão de ponto flutuante. Porque decimais são armazenados em binário, alguns valores não podem ser mantidos exatamente, então 0.1 + 0.2 não é bem 0.3:

js
console.log(0.1 + 0.2 === 0.3); // false

As correções práticas são arredondar para exibição, ou trabalhar em unidades inteiras. Dinheiro é o caso clássico: mantenha valores como centavos inteiros (1099 em vez de 10.99) e divida apenas quando você os mostra, o que evita o erro completamente.

js
const cents = 1099;
console.log(cents / 100); // 10.99, exato para exibição

O segundo é NaN, "não é um número", o resultado de uma operação sem resposta numérica tal como Number("hello") ou 0 / 0. Sua propriedade mais estranha é que não é igual a si mesma:

js
console.log(NaN === NaN); // false

Então você não pode testá-lo com ===. Use Number.isNaN(value), que retorna true apenas para NaN:

js
console.log(Number.isNaN(Number("hello"))); // true

Há também Infinity, o que você obtém de dividir por zero (1 / 0) ou ultrapassar o intervalo do número. Ele se comporta como um valor real em comparações mas sinaliza que um cálculo saiu da beira.

Três valores sentam nas arestas do tipo número, e um profissional precisa de todos os três na memória reflexa.

Imprecisão de ponto flutuante é a famosa. IEEE 754 armazena números em binário, e valores como 0.1 não têm representação binária exata, então aritmética acumula erro de arredondamento:

js
console.log(0.1 + 0.2); // 0.30000000000000004
console.log(0.1 + 0.2 === 0.3); // false

Nunca compare floats com === quando ambos os lados vieram de aritmética. Duas correções se sustentam em produção: arredonde para uma precisão fixa para exibição e comparação, ou, para qualquer coisa onde a exatidão é um requisito como moeda, trabalhe na menor unidade inteira e converta apenas na beira. Armazenar dinheiro como centavos inteiros (1099) e formatar na saída remove a classe de bug em vez de consertar uma instância dela.

js
const totalCents = 1099 + 250;
console.log(totalCents); // 1349, aritmética inteira exata

NaN é o valor de erro do tipo número, produzido por 0 / 0, Number("x"), e qualquer operação com resultado numérico indefinido. Tem uma propriedade única mandatada pela especificação: é o único valor não igual a si mesmo, então NaN === NaN é false. É por isso que verificações de identidade falham nele e por isso que Number.isNaN(x) existe como o teste confiável. Prefira a forma Number.isNaN sobre o isNaN global mais antigo, que força seu argumento primeiro e então relata true para coisas como "hello" que não são realmente NaN.

js
console.log(NaN === NaN); // false, NaN nunca é igual a si mesmo
console.log(Number.isNaN(0 / 0)); // true, o teste confiável

Infinity (e -Infinity) é o que você obtém de 1 / 0 ou de exceder o intervalo representável. É um valor real e comparável (Infinity > 1e308 é true), que o torna uma sentinela conveniente para "sem limite ainda" ao encontrar um mínimo, mas uma surpresa se alcançar uma exibição ou um banco de dados. Quando um resultado pode ultrapassar ou dividir por zero, decida qual é um fallback sensato antes de Infinity vazar a jusante.

JunoAs arestas afiadas dos números Decimais são armazenados um pouco solto, então 0.1 + 0.2 sai como 0.30000000000000004, que é normal, não um bug no seu código. Quando importa, arredonde o resultado antes de mostrá-lo. E NaN significa "não é um número", a resposta que você obtém quando uma conversão falha, então trate como uma pista que algum texto não se transformou em um número do jeito que você esperava.
JunoAs arestas afiadas dos números Ponto flutuante significa 0.1 + 0.2 não é exatamente 0.3, então arredonde para exibição ou trabalhe em unidades inteiras como centavos inteiros para dinheiro. NaN é o valor "sem resposta numérica", e sua armadilha é que NaN === NaN é false, então teste com Number.isNaN em vez disso. Infinity aparece de dividir por zero e significa que um cálculo saiu da beira.
JunoAs arestas afiadas dos números Nunca compare floats de aritmética com ===; arredonde para uma precisão ou mantenha dinheiro em centavos inteiros para que a classe de erro desapareça. NaN é o único valor não igual a si mesmo, que é exatamente por que Number.isNaN existe, e alcance por ele sobre o isNaN global que força. Infinity é um valor real e comparável de dividir por zero ou ultrapassagem, então dê a ele um fallback sensato antes de alcançar uma exibição ou um banco de dados.

Para onde números vão em seguida

Números são um de alguns tipos de dados principais em JavaScript, sentando ao lado de texto e valores verdadeiro/falso. A maioria dos programas reais os misturam, puxando um número de uma string, comparando, armazenando o resultado em uma variável, e os operadores que fazem essa comparação e combinação são o assunto de operadores em seguida.