Klasa `Number` w JavaScript
Ten artykuł wyjaśnia klasę Number w JavaScript.
Szczegółowo wyjaśnimy cechy charakterystyczne klasy Number, typowe pułapki, przydatne API oraz praktyczne przykłady krok po kroku.
YouTube Video
Klasa Number w JavaScript
Number to podstawowy typ liczbowy w JavaScript i jest reprezentowany jako liczba zmiennoprzecinkowa podwójnej precyzji według standardu IEEE-754 (64-bitowa).
Podstawy: Reprezentacja liczb i sprawdzanie typu
W JavaScript wszystkie liczby są reprezentowane jako prymitywny typ 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)
- Ten kod demonstruje różnicę pomiędzy prymitywnym
numbera obiektem opakowującymNumber. Zazwyczaj używa się prymitywów zamiast obiektów opakowujących.
Wartości specjalne: NaN, Infinity i stałe
Number udostępnia wartości specjalne (NaN, Infinity) oraz stałe.
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
- Liczby całkowite większe lub równe
MAX_SAFE_INTEGERmogą nie być reprezentowane dokładnie. Rozważ użycieBigInt, jeśli wymagana jest precyzja.EPSILONjest używany do porównywania liczb zmiennoprzecinkowych.
Konwersja liczb: Number(), parseInt, parseFloat oraz operator +
Istnieje kilka sposobów konwersji ciągu znaków na liczbę, z których każdy zachowuje się inaczej.
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()zwracaNaN, chyba że cały ciąg jest ściśle w formacie liczbowym, podczas gdyparseIntiparseFloatanalizują czytelną część liczbową od początku ciągu. Bezpieczniej jest zawsze jawnie określić podstawę systemu liczbowego (radix) przy użyciuparseInt.
Obsługa i sprawdzanie NaN: isNaN oraz Number.isNaN
NaN (Not-A-Number) jest wyjątkowy, ponieważ NaN !== NaN. Istnieją różnice w sposobie sprawdzania; globalna funkcja isNaN wykonuje konwersję typu i może dawać fałszywe pozytywy, dlatego zalecane jest użycie 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
- Używaj
Number.isNaNdo sprawdzania liczb i walidacji wyników obliczeń, aby uniknąć niepotrzebnej konwersji typów.
Błędy zmiennoprzecinkowe i porównania z wykorzystaniem Number.EPSILON
Ze względu na standard IEEE-754 występują błędy takie jak 0.1 + 0.2 !== 0.3. Do ścisłych porównań często wykorzystuje się różnicę oraz 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
- Przy dozwolonych błędach w porównaniu zaleca się użycie solidnej implementacji, takiej jak
nearlyEqual, która uwzględnia skalowanie oraz różnice bezwzględne.
Sprawdzenie liczb całkowitych i bezpiecznych liczb całkowitych (isInteger, isSafeInteger)
Istnieją API pozwalające sprawdzić, czy wartość jest liczbą całkowitą oraz czy mieści się ona w bezpiecznym zakresie liczb całkowitych.
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
- Gdy wymagana jest dokładność dużych liczb całkowitych, użyj
Number.isSafeIntegerdo sprawdzania, a dla liczb przekraczających ten zakres rozważ zastosowanieBigInt.
Wyświetlanie i formatowanie: toFixed, toPrecision, toString
Istnieją metody pozwalające kontrolować sposób wyświetlania liczb. toFixed zwraca napis o określonej liczbie miejsc po przecinku, ale należy uważać na zasady zaokrąglania.
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)
toFixedzwraca napis, więc trzeba uważać na wartości po ich zamianie na liczby w obliczeniach.
Ostrzeżenia dotyczące konkatenacji napisów i działania operatora +
Operator + jest używany zarówno do dodawania liczb, jak i do łączenia napisów, więc w zależności od typów danych mogą wystąpić nieoczekiwane rezultaty.
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)
- W przypadku mieszania napisów i liczb bezpieczniej jest jawnie używać
String(),Number()lub szablonów napisowych (template literals), aby uniknąć niejawnej konwersji typów.
Zaawansowane przypadki użycia: Number.parseInt / Number.parseFloat, valueOf
Number.parseInt i Number.parseFloat są aliasami funkcji globalnych. valueOf służy do pobierania prymitywnej wartości z obiektu Number, ale w praktyce rzadko się go używa.
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)
- Przy używaniu
Number.parseIntiNumber.parseFloatnależy uważać na podstawę systemu liczbowego oraz przycinanie (trimming) wejścia. Obiekty opakowujące są zazwyczaj unikane.
Referencja: Mały przykład pomocniczy – funkcje walidacji liczb
Oto małe funkcje pomocnicze, które zbierają najczęściej używane sprawdzenia. Ułatwia to takie zadania jak walidacja danych wejściowych.
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}- Są to bardzo uniwersalne funkcje, które można wielokrotnie wykorzystywać do przetwarzania danych wejściowych i porównań. Implementacje, które rzucają błędy, są przydatne w celach walidacji.
Podsumowanie wydajności i najlepszych praktyk
Oto praktyczne wskazówki dotyczące używania Number.
- Zasadniczo używaj prymitywnego typu
numberi unikajnew Number(). - Wybierz między
Number()(ścisłe) lubparseInt/parseFloat(częściowe wydobycie), zależnie od przypadku użycia przy konwersji napisu na liczbę. - Używaj
Number.isNaNiNumber.isFinitedla bezpiecznego sprawdzania. - Do porównań liczb zmiennoprzecinkowych używaj
Number.EPSILONlub dedykowanej funkcji porównującej. - Gdy wymagana jest dokładność liczb całkowitych, użyj
Number.isSafeInteger, a gdy przekraczają one zakres, użyjBigInt. - Możesz użyć
toFixedlubtoPrecisiondo zaokrąglania na potrzeby wyświetlania, ale pamiętaj, że wartość zwracana to łańcuch znaków.
Podsumowanie
Number to podstawowy typ wszystkich liczb w JavaScript, włączając liczby całkowite, dziesiętne i wartości specjalne (NaN i Infinity). Ważne jest, aby mieć świadomość konwersji typów i błędów zmiennoprzecinkowych, oraz poprawnie korzystać z metod takich jak Number.isNaN i Number.EPSILON. Jeśli przekroczony zostanie zakres bezpiecznych liczb całkowitych, użyj BigInt, natomiast do zaokrągleń i wyświetlania korzystaj z toFixed lub toPrecision.
Możesz śledzić ten artykuł, korzystając z Visual Studio Code na naszym kanale YouTube. Proszę również sprawdzić nasz kanał YouTube.