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

Números y matemáticas

docs.scrimba.com

Un carrito de compras suma precios, un juego rastrea una puntuación, un formulario calcula cuánto impuesto cobrar. Todo se reduce a números y hacer aritmética con ellos. JavaScript trata los números como uno de sus bloques de construcción fundamentales, y este capítulo trata sobre lo que puedes hacer con ellos: las matemáticas cotidianas, los ayudantes integrados para redondeo y aleatoriedad, y la parte que confunde a casi todos: convertir texto escrito en una página en números que puedas sumar.

Números y aritmética

JavaScript tiene un número de tipo, y cubre todo. Los números enteros como 42 y los decimales como 9.99 son el mismo tipo de valor, así que nunca tienes que elegir entre ellos:

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

Haces matemáticas con los símbolos que ya conoces: + suma, - resta, * multiplica, y / divide. Hay uno más que es menos familiar, %, el residuo. Te da lo que queda después de dividir:

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

Siete dividido por dos es tres con uno de residuo, así que 7 % 2 es 1. Así es como verificas si un número es par: un número par dividido por dos no deja residuo, así que number % 2 es 0 para números pares y 1 para números impares.

JavaScript tiene un único número de tipo para números enteros y decimales, así que 42 y 9.99 son el mismo tipo de valor. Esto es diferente a lenguajes que separan enteros y flotantes en tipos diferentes; aquí nunca declaras cuál significa.

Los cinco operadores aritméticos son +, -, *, /, y %. El operador residuo % devuelve lo que queda después de la división, y gana su lugar más de lo que los principiantes esperan:

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

Distribuir 17 elementos 5 por fila deja 2 en la última fila, y 17 % 5 te dice eso. El uso clásico es probar par u impar: count % 2 es 0 para números pares y 1 para números impares, que es cómo alternas colores de fila o divides una lista por la mitad.

Los operadores siguen la precedencia normal de matemáticas, así que *, /, y % se cierran más fuerte que + y -, y operadores de igual precedencia se leen de izquierda a derecha. Usa paréntesis cuando el orden importa:

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

JavaScript tiene un número de tipo, un valor flotante de 64 bits (el doble IEEE 754, la misma representación que la mayoría de lenguajes llama double). No hay un tipo entero separado en este nivel, lo que significa que 42, 9.99, y -3 son todo el mismo tipo de cosa, y cada entero que escribas es realmente un flotante que sucede no tener parte fraccionaria.

Los cinco operadores son + - * / %. El residuo % es el que vale la pena aclarar, porque es residuo, no módulo: toma el signo del operando izquierdo, así que -7 % 3 es -2, no 1. Para el caso cotidiano su valor es estable y útil. Probar n % 2 === 0 para par es el truco canónico, y se mantiene para negativos también ya que -4 % 2 sigue siendo 0.

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

La precedencia sigue matemáticas estándar: *, /, y % comparten un nivel por encima de + y -, y dentro de un nivel la evaluación es de izquierda a derecha (asociativa izquierda). La gramática completa es más estratificada que eso una vez que comparaciones y lógica entran, que es el tema de operadores. Para aritmética solamente la regla que necesitas es simple: multiplicativo antes que aditivo, pone entre paréntesis cualquier cosa en la que un lector tendría que detenerse. La claridad supera ahorrar tres caracteres.

js
const average = (a + b + c) / 3;
JunoNúmeros y aritmética Hay un tipo number en JavaScript, así que números enteros y decimales son lo mismo y nunca eliges entre ellos. Los operadores son + - * / más %, el residuo, que es lo que queda después de dividir. El truco útil es % 2: es 0 para números pares y 1 para números impares.
JunoNúmeros y aritmética Un tipo número cubre números enteros y decimales, así que no hay decisión int-versus-float que tomar. Los cinco operadores son + - * / y %, y % vale la pena recordar: count % 2 te da par-u-impar, y también te dice qué queda en una fila parcialmente llena. La precedencia es matemáticas normales, así que poner entre paréntesis cualquier cosa en la que un lector tendría que pensar.
JunoNúmeros y aritmética Cada número es un flotante de 64 bits, así que no hay tipo entero separado y 42 es un doble sin fracción. La única trampa en % es que es residuo, no módulo, así que toma el signo del lado izquierdo y -7 % 3 es -2. Para la prueba par-u-impar que nunca te muerde, ya que n % 2 === 0 se mantiene para negativos también.

El objeto Math

Cuando necesitas más que los operadores básicos, JavaScript te da Math, una colección integrada de ayudantes matemáticos. Los llamas por nombre con un punto:

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

Math.round redondea al número entero más cercano, Math.floor siempre redondea hacia abajo, y Math.ceil siempre redondea hacia arriba. También hay Math.max y Math.min, que eligen el más grande o el más pequeño de los números que les das:

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

Y Math.random, que te da un decimal aleatorio de 0 hasta (pero no incluyendo) 1. Por sí solo eso es raramente lo que quieres, así que la receta común es multiplicarlo y usar floor para obtener un número entero aleatorio:

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

Math.random() * 6 cae en algún lugar de 0 hasta 6, Math.floor lo deja caer a un número entero de 0 a 5, y + 1 lo desplaza a una tirada de dados de 1 a 6.

Math es un objeto integrado que contiene funciones y constantes matemáticas. No lo creas; siempre está ahí, y llamas sus métodos con un punto.

El trío de redondeo es el que alcanzas la mayoría de las veces:

js
console.log(Math.round(4.5)); // 5, número entero más cercano
console.log(Math.floor(4.9)); // 4, siempre hacia abajo
console.log(Math.ceil(4.1)); // 5, siempre hacia arriba

Math.max y Math.min devuelven el más grande y el más pequeño de sus argumentos, que es útil para fijar un valor en un rango:

js
const clamped = Math.min(Math.max(userValue, 0), 100);
console.log(clamped); // se mantiene entre 0 y 100

Math.random devuelve un flotante en el rango [0, 1), lo que significa que 0 es posible pero 1 nunca lo es. Para convertir eso en un número entero aleatorio de 0 hasta n, el patrón es Math.floor(Math.random() * n):

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

La multiplicación extiende el rango a [0, n), y floor corta el decimal así aterrizas en un número entero. Añade un desplazamiento cuando quieras un rango que no comience en cero, como + 1 para una tirada de dados.

Math es un objeto de espacio de nombres estático: un contenedor simple de métodos y constantes matemáticas, no algo que instantees. Cada método se llama como Math.something(), y hay exactamente uno Math en el tiempo de ejecución.

Los métodos de redondeo cada uno redondean hacia un objetivo diferente: Math.round al más cercano (los empates van hacia arriba, así que Math.round(2.5) es 3 pero Math.round(-2.5) es -2), Math.floor hacia el infinito negativo, Math.ceil hacia el infinito positivo. Esa distinción floor-no-es-truncamiento importa para negativos, donde Math.floor(-1.2) es -2, no -1.

js
console.log(Math.floor(-1.2)); // -2, floor va hacia abajo incluso para negativos

Math.max y Math.min toman cualquier cantidad de argumentos y son la manera limpia de fijar:

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

Math.random devuelve un flotante distribuido uniformemente en [0, 1). El modismo para un entero aleatorio es Math.floor(Math.random() * range) + start: escala por el ancho del rango, floor a un entero, desplaza por el inicio. Dos advertencias que vale la pena llevar: no es criptográficamente seguro, así que nunca lo uses para tokens o cualquier cosa que un usuario no deba poder adivinar (crypto.getRandomValues existe para eso), y los errores fuera por uno vienen de confundir límites inclusivos y exclusivos, así que decide por adelantado si tu valor superior es alcanzable.

js
const dice = Math.floor(Math.random() * 6) + 1;
console.log(dice); // 1 a 6 inclusive
JunoEl objeto MathMath es una caja de herramientas lista de ayudantes matemáticos que llamas con un punto: Math.round, Math.floor (hacia abajo), Math.ceil (hacia arriba), y Math.max / Math.min para el más grande y el más pequeño. Math.random te da un decimal de 0 hasta 1, y la receta que vale la pena memorizar es Math.floor(Math.random() * n) para un número entero aleatorio. Me tomó algunos intentos confiar en ese patrón, así que cópialo y léelo lentamente.
JunoEl objeto MathMath siempre está ahí, sin configuración necesaria, y llamas sus métodos con un punto. Mantén el trío de redondeo recto: round al más cercano, floor hacia abajo, ceil hacia arriba, y usa min y max juntos para fijar un valor en un rango. Para aleatoriedad, Math.floor(Math.random() * n) te da un número entero de 0 hasta n, y un desplazamiento mueve el rango.
JunoEl objeto MathMath es un espacio de nombres estático, así que hay uno de él y nada que construir. Observa los objetivos de redondeo en negativos: Math.floor(-1.2) es -2, no truncamiento, y Math.round rompe los empates hacia arriba. Math.floor(Math.random() * range) + start es el modismo entero, pero Math.random no es seguro, así que usa crypto.getRandomValues para cualquier cosa que un usuario no deba adivinar.

Convertir cadenas en números

Cualquier cosa que una persona escriba en una página llega como texto, incluso cuando se parece a un número. Escribe 5 en un cuadro y obtienes la cadena "5", no el número 5. Eso importa porque + en dos cadenas las une en lugar de sumar:

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

Para hacer matemáticas, conviertes el texto en un número primero. La manera más clara es Number():

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

Hay dos más que verás: parseInt lee un número entero y descarta cualquier decimal, y parseFloat mantiene el decimal:

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

Ambos pueden leer un número sentado al inicio de algún texto, como "42px", que Number no puede. También hay un atajo, un + frente a una cadena, que la convierte de la misma manera que lo hace Number:

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

La entrada de una página es siempre una cadena. Un campo de formulario, una URL, un atributo de datos: todo texto, incluso "5". Como + concatena cadenas, sumar dos valores de texto los une en lugar de sumarlos, que es el error de números más común para principiantes:

js
const price = "10";
const shipping = "5";
console.log(price + shipping); // "105", concatenación de cadenas

Convierte antes de calcular. Number() es la opción estricta y legible: convierte una cadena numérica limpia en un número y da NaN para cualquier cosa que no sea totalmente numérica.

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

parseInt y parseFloat son más indulgentes. Leen un número desde el frente de una cadena y se detienen en el primer carácter que no encaja, que es por qué parseInt("42px") es 42. parseInt descarta cualquier parte fraccionaria; parseFloat la mantiene:

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

Pasa 10 como el segundo argumento a parseInt así siempre lee base diez. El unario + es un conversor conciso que se comporta como Number: usa Number() para valores completos, parseInt/parseFloat para números incrustados en texto.

El texto del mundo exterior es siempre una cadena, y porque + se sobrecarga para concatenación, "10" + "5" es "105". Cada operador aritmético excepto + coerciona sus operandos a números, así que "10" * 1 es 10, pero depender de eso es una trampa de legibilidad. Convierte deliberadamente.

Number() es coerción de cadena completa: tiene éxito solo si la cadena trimmed completa es un literal numérico válido, de lo contrario NaN. Entiende hexadecimales (Number("0x1f") es 31), exponentes, y espacios en blanco al inicio o al final, y trata "" como 0, que es un borde afilado que vale la pena saber.

js
console.log(Number("")); // 0, uno afilado para perder
console.log(Number("  12 ")); // 12, espacio en blanco trimmed
console.log(Number("12abc")); // NaN

parseInt y parseFloat analizan un prefijo: leen tan lejos como pueden e ignoran el resto, así que parseInt("12abc") es 12. Siempre da a parseInt su raíz (parseInt(str, 10)); sin ella, una entrada como "0x10" se lee como hexadecimal. El unario + es la forma más corta de coerción Number y aparece a menudo en código conciso (+"3.5" es 3.5), con las mismas reglas y la misma sorpresa de "" se convierte en 0.

La regla práctica: Number (o +) cuando el valor completo debe ser numérico y cualquier otra cosa es un error que quieres capturar, parseInt/parseFloat cuando un número está incrustado en texto que esperas. Sea lo que sea que elijas, el resultado puede ser NaN, que es lo que trata la próxima sección. Comparación y coerción más allá de esto viven en operadores, y el lado de cadena de la historia está en cadenas.

JunoConvertir cadenas en números Cualquier cosa escrita en una página es texto, así que "5" no es el número 5, y "5" + "3" da "53" en lugar de 8. Convierte primero: Number("5") es la más clara, parseInt lee un número entero, parseFloat mantiene decimales, y un + frente a una cadena es un atajo rápido. Observa la trampa de unión-en-lugar-de-suma, atrapa a todos una vez.
JunoConvertir cadenas en números La entrada de página es siempre una cadena, y como + une cadenas, "10" + "5" es "105", el error de números más común que existe. Usa Number() cuando el valor completo debe ser numérico, y parseInt o parseFloat cuando un número está sentado dentro de texto como "42px". Dale a parseInt su argumento base-diez y no te sorprenderá.
JunoConvertir cadenas en números Cada operador excepto + coerciona a número, así que "10" * 1 funciona, pero convierte a propósito en lugar de eso. Number() exige que la cadena completa sea numérica y silenciosamente convierte "" en 0, mientras que parseInt y parseFloat analizan un prefijo e ignoran el resto, así que siempre pasa a parseInt una raíz de 10. Cualquiera de ellos puede darte NaN, que es lo siguiente con lo que debes estar cómodo.

Los bordes afilados de los números

Los números en JavaScript tienen una sorpresa que vale la pena ver una vez, temprano. Suma dos decimales simples y puedes obtener una respuesta extraña:

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

Eso no es un error en tu código. Las computadoras almacenan decimales de una manera que no puede representar cada valor exactamente, así que un pequeño error se cuela. Raramente importa, y cuando importa, redondeas el resultado para exhibición:

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

También conocerás un valor llamado NaN, abreviatura de "no es un número". Lo obtienes cuando una operación matemática no tiene una respuesta sensata, como intentar convertir texto sin sentido en un número:

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

Ver NaN en tu salida generalmente significa que una conversión fue mal en algún lugar, así que es una pista útil en lugar de algo que temer.

Dos valores numéricos te sorprenderán eventualmente, y es mejor conocerlos a propósito.

El primero es imprecisión de punto flotante. Porque los decimales se almacenan en binario, algunos valores no se pueden mantener exactamente, así que 0.1 + 0.2 no es exactamente 0.3:

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

Las soluciones prácticas son redondear para exhibición, o trabajar en unidades completas. El dinero es el caso clásico: mantener cantidades como centavos enteros (1099 en lugar de 10.99) y dividir solo cuando las muestres, que evita el error completamente.

js
const cents = 1099;
console.log(cents / 100); // 10.99, exacto para exhibición

El segundo es NaN, "no es un número", el resultado de una operación sin respuesta numérica como Number("hello") o 0 / 0. Su propiedad más extraña es que no es igual a sí mismo:

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

Así que no puedes probarlo con ===. Usa Number.isNaN(value), que devuelve true solo para NaN:

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

También está Infinity, lo que obtienes de dividir por cero (1 / 0) o sobrepasar el rango de números. Se comporta como un valor real en comparaciones pero señala que un cálculo se ha corrido al borde.

Tres valores se sientan en los bordes del tipo número, y un profesional necesita los tres en memoria de reflejo.

La imprecisión de punto flotante es la famosa. IEEE 754 almacena números en binario, y valores como 0.1 no tienen representación binaria exacta, así que la aritmética acumula error de redondeo:

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

Nunca compares flotantes con === cuando cualquiera de los lados vino de aritmética. Dos soluciones se mantienen en producción: redondea a una precisión fija para exhibición y comparación, o, para cualquier cosa donde la exactitud es un requisito como moneda, trabaja en la unidad entera más pequeña y solo convierte en el límite. Almacenar dinero como centavos enteros (1099) y formatear en salida elimina la clase de error en lugar de parchear una instancia de ella.

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

NaN es el valor de error del tipo número, producido por 0 / 0, Number("x"), y cualquier operación con un resultado numérico indefinido. Tiene una propiedad única mandatada por la especificación: es el único valor no igual a sí mismo, así que NaN === NaN es false. Esa es por qué los controles de identidad fallan en él y por qué existe Number.isNaN(x) como la prueba confiable. Prefiere la forma Number.isNaN sobre el más antiguo global isNaN, que coerciona su argumento primero y así reporta true para cosas como "hello" que no son actualmente NaN.

js
console.log(NaN === NaN); // false, NaN nunca se iguala a sí mismo
console.log(Number.isNaN(0 / 0)); // true, la prueba confiable

Infinity (e -Infinity) es lo que obtienes de 1 / 0 o de exceder el rango representable. Es un valor real comparable (Infinity > 1e308 es true), que lo hace una centinela conveniente para "sin límite aún" cuando encuentras un mínimo, pero una sorpresa si llega a exhibición o a una base de datos. Cuando un resultado puede desbordarse o dividir por cero, decide cuál es un retroceso sensato antes de que Infinity se escape corriente abajo.

JunoLos bordes afilados de los números Los decimales se almacenan un poco flojamente, así que 0.1 + 0.2 resulta ser 0.30000000000000004, que es normal, no un error en tu código. Cuando importa, redondea el resultado antes de mostrarlo. Y NaN significa "no es un número", la respuesta que obtienes cuando una conversión falla, así que tíralo como una pista de que algún texto no se convirtió en un número como esperabas.
JunoLos bordes afilados de los números Punto flotante significa que 0.1 + 0.2 no es exactamente 0.3, así que redondea para exhibición o trabaja en unidades completas como centavos enteros para dinero. NaN es el valor "sin respuesta numérica", y su trampa es que NaN === NaN es false, así que prueba con Number.isNaN en lugar de eso. Infinity aparece de dividir por cero y significa que un cálculo se corrió al borde.
JunoLos bordes afilados de los números Nunca compares flotantes de aritmética con ===; redondea a una precisión o mantén dinero en centavos enteros así la clase de error desaparece. NaN es el único valor no igual a sí mismo, que es exactamente por qué existe Number.isNaN, y alcanza hacia él sobre el coercitivo global isNaN. Infinity es un valor real comparable de dividir-por-cero o desbordamiento, así que dale un retroceso sensato antes de que llegue a exhibición o una base de datos.

Hacia dónde van los números a continuación

Los números son uno de un puñado de tipos de datos centrales en JavaScript, sentándose junto a texto y valores verdadero/falso. La mayoría de programas reales los mezclan, sacando un número de una cadena, comparándolo, almacenando el resultado en una variable, y los operadores que hacen esa comparación y combinación son el tema de operadores a continuación.