מחלקת `Number` ב-JavaScript

מחלקת `Number` ב-JavaScript

מאמר זה מסביר את מחלקת Number ב-JavaScript.

נסביר בזהירות את המאפיינים של Number, מלכודות נפוצות, APIs שימושיים, ודוגמאות מעשיות שלב אחר שלב.

YouTube Video

מחלקת Number ב-JavaScript

Number הוא טיפוס המספרים הבסיסי ב-JavaScript ומיוצג כמספר נקודה צפה בדיוק כפול (64-ביט) לפי תקן IEEE-754.

יסודות: ייצוג מספרים ובדיקת טיפוס

ב-JavaScript, כל המספרים מיוצגים כטיפוס הבסיסי 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)
  • הקוד הזה מדגים את ההבדל בין טיפוס פרימיטיבי number לבין האובייקט העוטף Number. בדרך כלל נעשה שימוש בערכים בסיסיים (primitives) במקום עוטפים (wrappers).

ערכים מיוחדים: NaN, Infinity וקבועים

Number מספק ערכים מיוחדים (NaN, Infinity) וקבועים.

 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
  • מספרים שלמים הגדולים או שווים ל-MAX_SAFE_INTEGER עשויים לא להיות מיוצגים בדיוק. שקול להשתמש ב-BigInt אם דרושה דיוק גבוה. EPSILON משמש להשוואת מספרים בנקודה צפה.

המרת מספרים: Number(), parseInt, parseFloat, והאופרטור +

ישנן מספר דרכים להמיר מחרוזת למספר, שלכל אחת מהן התנהגות שונה.

 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() מחזיר NaN אלא אם כל המחרוזת בפורמט מספרי בלבד, בעוד ש-parseInt ו-parseFloat מפענחים את החלק המספרי שקיים בתחילת המחרוזת. בטוח יותר לציין תמיד את בסיס המספר (radix) בעת שימוש ב-parseInt.

טיפול ובדיקה של NaN: הפונקציות isNaN ו-Number.isNaN

NaN (לא מספר) הוא מיוחד כי NaN !== NaN. יש הבדל באופן הבדיקה; isNaN הגלובלית מבצעת המרת טיפוס ועלולה לגרום לתוצאות חיוביות שגויות, לכן מומלץ להשתמש ב-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
  • השתמש ב-Number.isNaN לבדיקה של מספרים ואימות תוצאות חישוב כדי להימנע מהמרות טיפוס מיותרות.

שגיאות נקודה צפה והשוואות בעזרת Number.EPSILON

בגלל תקן IEEE-754, מתרחשות שגיאות כמו 0.1 + 0.2 !== 0.3. להשוואות מדויקות נהוג להשתמש בהפרש ו-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
  • כשמתירים שגיאות בהשוואה, מומלץ ליישם פונקציה חזקה כמו nearlyEqual, שמבצעת גם קנה מידה וגם משתמשת בהפרשים מוחלטים.

בדיקת שלמים ושלמים בטוחים (isInteger, isSafeInteger)

יש APIs שמאפשרים לבדוק אם ערך הוא שלם ואם הוא נמצא בתחום המספרים השלמים הבטוחים.

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
  • כאשר נדרשת דיוק עבור שלמים גדולים, השתמש ב-Number.isSafeInteger לבדיקה, ושקול להשתמש ב-BigInt עבור מספרים שמעל הטווח.

הצגה ועיצוב: toFixed, toPrecision, toString

ישנן שיטות לשליטה על אופן ההצגה של מספרים. toFixed מחזיר מחרוזת עם מספר ספרות אחרי הנקודה בהתאם למשתנה שניתן, אך יש לשים לב לעיגול.

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 מחזיר מחרוזת, לכן יש לשים לב לערכים לאחר המרה למספרים לצורך חישובים.

זהירות לגבי שרשור מחרוזות ואופרטור +

האופרטור + משמש גם לחיבור מספרים וגם לשרשור מחרוזות, ולכן עשויות להתרחש תוצאות לא צפויות בהתאם לטיפוסי הנתונים.

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)
  • כאשר מערבבים מחרוזות ומספרים, בטוח יותר להשתמש במפורש ב-String(), Number() או ב-template literals כדי להימנע מהמרות טיפוס מרומזות.

שימושים מתקדמים: Number.parseInt / Number.parseFloat, valueOf

Number.parseInt ו-Number.parseFloat הן כינויים לפונקציות הגלובליות. valueOf משמש לקבלת הערך הבסיסי מתוך אובייקט Number, אך לרוב אין בו צורך מעשי.

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)
  • בעת שימוש ב-Number.parseInt ו-Number.parseFloat, יש לשים לב לבסיס המספר (radix) ולחיתוך (trimming) הקלט. נהוג בדרך כלל להימנע משימוש בעוטפי טיפוסים (Wrapper objects).

הפניה: דוגמת עזר קטנה - פונקציות לאימות מספרים

להלן פונקציות עזר קטנות שמאגדות בדיקות נפוצות. דבר זה מקל על משימות כגון אימות קלט.

 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}
  • אלו פונקציות שימושיות במיוחד שיכולות לשמש לעיבוד קלט ולהשוואות שוב ושוב. מימושים שזורקים חריגות (errors) מועילים למטרות ולידציה.

סיכום ביצועים והמלצות לשימוש מיטבי

להלן נקודות מעשיות לשימוש ב-Number.

  • בעיקרון, השתמש בטיפוס number הבסיסי והימנע משימוש ב-new Number().
  • בחר בין Number() (מדויק) או parseInt/parseFloat (חילוץ חלקי) להמרת מחרוזת למספר בהתאם לצורך.
  • השתמש ב-Number.isNaN ו-Number.isFinite לבדיקות בטוחות.
  • להשוואות מספרים בנקודה צפה השתמש ב-Number.EPSILON או כתוב פונקציה להשוואה ייעודית.
  • כשדרושה דיוק בשלם, בדוק עם Number.isSafeInteger, ואם חורגים מהטווח, השתמש ב-BigInt.
  • אתה יכול להשתמש ב-toFixed או toPrecision לעיגול בעת תצוגה, אך שים לב שערך ההחזרה הוא מחרוזת.

סיכום

Number הוא הטיפוס הבסיסי לכל המספרים ב-JavaScript, כולל שלמים, עשרוניים וערכים מיוחדים (NaN ו-Infinity). חשוב לשים לב להמרות טיפוס ולשגיאות נקודה צפה, ולהשתמש נכון בשיטות כמו Number.isNaN ו-Number.EPSILON. אם חורגים מטווח המספרים השלמים הבטוחים, השתמש ב-BigInt ועבור עיגול או הצגה השתמש ב-toFixed או toPrecision.

תוכלו לעקוב אחר המאמר שלמעלה באמצעות Visual Studio Code בערוץ היוטיוב שלנו. נא לבדוק גם את ערוץ היוטיוב.

YouTube Video