La classe `Number` in JavaScript

La classe `Number` in JavaScript

Questo articolo spiega la classe Number in JavaScript.

Spiegheremo attentamente le caratteristiche di Number, le insidie comuni, le API utili e degli esempi pratici passo dopo passo.

YouTube Video

La classe Number in JavaScript

Number è il tipo numerico fondamentale in JavaScript ed è rappresentato come un float a doppia precisione IEEE-754 (64 bit).

Nozioni di base: Rappresentazione dei numeri e controllo del tipo

In JavaScript, tutti i numeri sono rappresentati come tipo primitivo number.

 1// Primitive numbers and Number object
 2const a = 42;                 // primitive number
 3const b = 3.14;               // primitive float
 4const c = Number(10);         // primitive via constructor call (function form)
 5const d = new Number(10);     // Number object (wrapper)
 6
 7console.log(typeof a);        // "number"
 8console.log(typeof d);        // "object"
 9console.log(c == d);          // true  (value coerces)
10console.log(c === d);         // false (different types)
  • Questo codice dimostra la differenza tra un tipo primitivo number e l’oggetto wrapper Number. Normalmente si usano i primitivi invece dei wrapper.

Valori speciali: NaN, Infinity e costanti

Number fornisce valori speciali (NaN, Infinity) e costanti.

 1// Special numeric values and constants
 2console.log(Number.NaN);                 // NaN
 3console.log(Number.POSITIVE_INFINITY);   // Infinity
 4console.log(Number.NEGATIVE_INFINITY);   // -Infinity
 5
 6console.log(Number.MAX_VALUE);           // largest positive representable
 7console.log(Number.MIN_VALUE);           // smallest positive representable (closest to 0)
 8console.log(Number.MAX_SAFE_INTEGER);    // 9007199254740991
 9console.log(Number.MIN_SAFE_INTEGER);    // -9007199254740991
10console.log(Number.EPSILON);             // smallest difference ~2.220446049250313e-16
  • Gli interi maggiori o uguali a MAX_SAFE_INTEGER potrebbero non essere rappresentati accuratamente. Prendi in considerazione l'uso di BigInt se è richiesta precisione. EPSILON viene utilizzato per i confronti tra numeri in virgola mobile.

Conversione dei numeri: Number(), parseInt, parseFloat e operatore +

Esistono diversi modi per convertire una stringa in un numero, ognuno con comportamenti differenti.

 1// Converting strings to numbers
 2console.log(Number("42"));        // 42
 3console.log(Number("  3.14 "));   // 3.14
 4console.log(+ "7");               // 7 (unary +)
 5
 6console.log(parseInt("42px"));    // 42
 7console.log(parseFloat("3.14abc"));// 3.14
 8
 9// Careful with parseInt and radix
10console.log(parseInt("08"));      // 8
11console.log(parseInt("08", 10));  // 8 (explicit radix is safer)
  • Number() restituisce NaN a meno che l'intera stringa non sia in formato numerico puro, mentre parseInt e parseFloat analizzano la parte numerica leggibile dall'inizio della stringa. È più sicuro specificare sempre esplicitamente la base quando si utilizza parseInt.

Gestione e verifica di NaN: isNaN e Number.isNaN

NaN (Not-A-Number) è speciale perché NaN !== NaN. Ci sono differenze nel modo in cui controllano; la funzione globale isNaN esegue una conversione di tipo e può portare a falsi positivi, quindi si consiglia di usare Number.isNaN.

1// NaN detection differences
2console.log(NaN === NaN);             // false
3
4console.log(isNaN("foo"));            // true  -> because "foo" coerces to NaN
5console.log(Number.isNaN("foo"));     // false -> "foo" is not the numeric NaN
6
7console.log(Number.isNaN(NaN));       // true
  • Usa Number.isNaN per verificare i numeri e validare i risultati dei calcoli per evitare conversioni di tipo non necessarie.

Errori di virgola mobile e confronti con Number.EPSILON

A causa dello standard IEEE-754 si verificano errori come 0.1 + 0.2 !== 0.3. Per confronti rigorosi è comune usare la differenza e Number.EPSILON.

1// Floating point precision example and EPSILON comparison
2const sum = 0.1 + 0.2;
3console.log(sum === 0.3);             // false
4
5function nearlyEqual(a, b, epsilon = Number.EPSILON) {
6  return Math.abs(a - b) <= epsilon * Math.max(1, Math.abs(a), Math.abs(b));
7}
8
9console.log(nearlyEqual(sum, 0.3));   // true
  • Quando si tollerano errori nei confronti, è consigliata un'implementazione robusta come nearlyEqual che esegue anche lo scaling oltre all'uso delle differenze assolute.

Verifica di interi e interi sicuri (isInteger, isSafeInteger)

Ci sono API per verificare se un valore è un intero e se rientra nell'intervallo degli interi sicuri.

1// Integer and safe integer checks
2console.log(Number.isInteger(3));                 // true
3console.log(Number.isInteger(3.0));               // true
4console.log(Number.isInteger(3.1));               // false
5
6console.log(Number.isSafeInteger(Number.MAX_SAFE_INTEGER)); // true
7console.log(Number.isSafeInteger(Number.MAX_SAFE_INTEGER + 1)); // false
  • Quando è richiesta la precisione di grandi numeri interi, usa Number.isSafeInteger per controllare e considera l'uso di BigInt per numeri che superano tale intervallo.

Visualizzazione e formattazione: toFixed, toPrecision, toString

Sono disponibili metodi per controllare la visualizzazione dei numeri. toFixed restituisce una stringa con un numero specificato di cifre decimali, ma bisogna fare attenzione all'arrotondamento.

1// Formatting numbers for display
2const x = 1.23456;
3console.log(x.toFixed(2));         // "1.23"   (string)
4console.log(x.toPrecision(3));     // "1.23"   (string with total significant digits)
5console.log((255).toString(16));   // "ff"     (hexadecimal string)
  • toFixed restituisce una stringa, perciò presta attenzione ai valori dopo averli convertiti nuovamente in numeri per i calcoli.

Avvertenze sulla concatenazione di stringhe e sull'operatore +

L'operatore + viene utilizzato sia per la somma numerica che per la concatenazione di stringhe, quindi possono verificarsi risultati indesiderati a seconda dei tipi di dati coinvolti.

1// Pitfall with + operator and type coercion
2console.log(1 + 2 + "px");    // "3px"
3console.log("px" + 1 + 2);    // "px12"
4console.log(1 + "2" - 0);     // 3  (string coerced to number for subtraction)
  • Quando vengono mescolati stringhe e numeri, è più sicuro usare esplicitamente String(), Number() o i template literal per evitare conversioni di tipo implicite.

Casi d'uso avanzati: Number.parseInt / Number.parseFloat, valueOf

Number.parseInt e Number.parseFloat sono alias delle funzioni globali. valueOf viene utilizzato per ottenere il valore primitivo da un oggetto Number, ma è raramente necessario nella pratica.

1// Number.parseInt/parseFloat aliases and valueOf example
2console.log(Number.parseInt("100", 10));   // 100
3console.log(Number.parseFloat("3.14"));    // 3.14
4
5const nObj = new Number(5);
6console.log(nObj.valueOf());               // 5
7console.log(nObj + 1);                     // 6  (object coerced to primitive)
  • Quando utilizzi Number.parseInt e Number.parseFloat, fai attenzione alla base e alla rimozione degli spazi nell'input. Gli oggetti wrapper generalmente vengono evitati.

Riferimento: Esempio di piccola utilità - Funzioni di validazione dei numeri

Ecco delle piccole funzioni di utilità che raccolgono controlli comunemente usati. Questo rende più semplici attività come la validazione degli input.

 1// Small number utility functions
 2function toNumberStrict(value) {
 3  // Return a Number or throw for invalid numeric strings
 4  const n = Number(value);
 5  if (typeof value === "string" && value.trim() === "") {
 6    throw new Error("Empty string is not a valid number");
 7  }
 8  if (Number.isNaN(n)) {
 9    throw new Error(`Invalid number: ${value}`);
10  }
11  return n;
12}
13
14function almostEqual(a, b, eps = Number.EPSILON) {
15  // Robust relative comparison
16  return Math.abs(a - b) <= eps * Math.max(1, Math.abs(a), Math.abs(b));
17}
  • Si tratta di funzioni molto versatili che possono essere riutilizzate per l'elaborazione degli input e i confronti. Implementazioni che generano errori sono utili a fini di validazione.

Riepilogo sulle prestazioni e sulle migliori pratiche

Ecco alcuni punti pratici nell'uso di Number.

  • Fondamentalmente, usa il tipo primitivo number ed evita new Number().
  • Scegli tra Number() (rigoroso) o parseInt/parseFloat (estrazione parziale) per la conversione da stringa a numero a seconda del caso d'uso.
  • Usa Number.isNaN e Number.isFinite per controlli sicuri.
  • Per confronti in virgola mobile, usa Number.EPSILON oppure crea una funzione dedicata.
  • Quando è richiesta precisione sugli interi, usa Number.isSafeInteger e se il valore supera l'intervallo, usa BigInt.
  • Puoi usare toFixed o toPrecision per arrotondare a scopo di visualizzazione, ma nota che il valore restituito è una stringa.

Riepilogo

Number è il tipo di base per tutti i numeri in JavaScript, inclusi interi, decimali e valori speciali (NaN e Infinity). È importante essere consapevoli della conversione dei tipi e degli errori di virgola mobile, utilizzando correttamente metodi come Number.isNaN e Number.EPSILON. Se viene superato l'intervallo degli interi sicuri, usa BigInt e utilizza toFixed o toPrecision per arrotondamenti e visualizzazione.

Puoi seguire l'articolo sopra utilizzando Visual Studio Code sul nostro canale YouTube. Controlla anche il nostro canale YouTube.

YouTube Video