JavaScript Tutorial

Number Object in JavaScript: Complete Guide with Examples

Master JavaScript numbers — parseInt, parseFloat, toFixed, toPrecision, isNaN, isFinite, isInteger, Number limits, floating point issues, number formatting, and real-world examples with best practices.

Welcome back! 👋 In the previous lesson, you mastered the Math object. Now let's go deep on something you've been using since lesson one — Numbers — and understand how they really work in JavaScript!

Numbers in JavaScript are more nuanced than they appear. From floating point surprises to parsing strings, from formatting currency to checking if a value is actually a number — the Number object and its methods give you complete control. Understanding this deeply will save you from subtle bugs that trip up even experienced developers.

Let's master it completely!


How JavaScript Stores Numbers

JavaScript uses a single number type — IEEE 754 double-precision floating-point — for all numbers. There's no separate int or float type like other languages.

console.log(typeof 42);      // "number"
console.log(typeof 3.14);    // "number"
console.log(typeof -7);      // "number"
console.log(typeof Infinity); // "number"
console.log(typeof NaN);     // "number" — yes, NaN is a number type!

This means integers and decimals are the same type under the hood — which leads to some important quirks.


The Floating Point Problem

This is the most famous JavaScript gotcha — and it trips up developers at every level.

// ❌ You'd expect this to be 0.3 — it's not!
console.log(0.1 + 0.2); // 0.30000000000000004

// More examples
console.log(0.1 + 0.2 === 0.3); // false ❌
console.log(1.1 + 2.2);         // 3.3000000000000003
console.log(0.3 - 0.1);         // 0.19999999999999998

This happens because binary floating-point can't represent 0.1 exactly — just like you can't write 1/3 as a finite decimal.

How to Fix It

// ✅ Method 1: Use toFixed() and parseFloat
let result = parseFloat((0.1 + 0.2).toFixed(2));
console.log(result);          // 0.3
console.log(result === 0.3);  // true ✅

// ✅ Method 2: Work in integers (paise/cents)
// Store ₹100.50 as 10050 paise — do all math as integers
let price1 = 10;  // 10 paise = ₹0.10
let price2 = 20;  // 20 paise = ₹0.20
let sum    = price1 + price2; // 30 paise = ₹0.30 ✅
console.log(sum / 100);       // 0.3 ✅

// ✅ Method 3: Use Number.EPSILON for comparisons
function isEqual(a, b) {
  return Math.abs(a - b) < Number.EPSILON;
}
console.log(isEqual(0.1 + 0.2, 0.3)); // true ✅

Number Limits and Special Values

// Largest safe integer JavaScript can represent exactly
console.log(Number.MAX_SAFE_INTEGER); // 9007199254740991 (2^53 - 1)
console.log(Number.MIN_SAFE_INTEGER); // -9007199254740991

// Largest and smallest finite numbers
console.log(Number.MAX_VALUE);        // 1.7976931348623157e+308
console.log(Number.MIN_VALUE);        // 5e-324 (closest to 0, not negative!)

// Special values
console.log(Number.POSITIVE_INFINITY); // Infinity
console.log(Number.NEGATIVE_INFINITY); // -Infinity
console.log(Number.NaN);               // NaN
console.log(Number.EPSILON);           // 2.220446049250313e-16

Infinity and -Infinity

console.log(1 / 0);    // Infinity
console.log(-1 / 0);   // -Infinity
console.log(Infinity + 1);    // Infinity
console.log(Infinity - Infinity); // NaN

// Check for infinity
console.log(isFinite(1000));     // true
console.log(isFinite(Infinity)); // false
console.log(isFinite(NaN));      // false

NaN — Not a Number

NaN is a special value that results from invalid numeric operations.

console.log(0 / 0);              // NaN
console.log("hello" * 2);        // NaN
console.log(Math.sqrt(-1));       // NaN
console.log(parseInt("abc"));    // NaN
console.log(undefined + 1);      // NaN

Checking Numbers

Number.isNaN() — Is it NaN?

// ✅ Number.isNaN() — strict, only true for actual NaN
console.log(Number.isNaN(NaN));          // true  ✅
console.log(Number.isNaN("hello"));      // false ✅ (it's a string, not NaN)
console.log(Number.isNaN(undefined));    // false ✅

// ⚠️ Global isNaN() — converts first, then checks — can be misleading!
console.log(isNaN("hello"));    // true  — converts "hello" to NaN first
console.log(isNaN(undefined));  // true  — converts undefined to NaN first

// ✅ Always prefer Number.isNaN() over global isNaN()

Number.isFinite() — Is it a finite number?

console.log(Number.isFinite(100));       // true
console.log(Number.isFinite(Infinity));  // false
console.log(Number.isFinite(-Infinity)); // false
console.log(Number.isFinite(NaN));       // false
console.log(Number.isFinite("100"));     // false — string, not a number

Number.isInteger() — Is it a whole number?

console.log(Number.isInteger(42));      // true
console.log(Number.isInteger(42.0));    // true  (42.0 === 42 in JS)
console.log(Number.isInteger(42.5));    // false
console.log(Number.isInteger("42"));    // false — string
console.log(Number.isInteger(Infinity)); // false

Number.isSafeInteger() — Can it be represented exactly?

console.log(Number.isSafeInteger(42));                    // true
console.log(Number.isSafeInteger(9007199254740991));      // true  (MAX_SAFE)
console.log(Number.isSafeInteger(9007199254740992));      // false (too large!)
console.log(Number.isSafeInteger(3.5));                   // false

Converting Strings to Numbers

parseInt() — String to Integer

Parses a string and returns an integer. Stops at the first non-numeric character.

console.log(parseInt("42"));        // 42
console.log(parseInt("42.9"));      // 42   — drops decimal
console.log(parseInt("42px"));      // 42   — stops at 'p'
console.log(parseInt("  42  "));    // 42   — trims whitespace
console.log(parseInt("abc"));       // NaN  — no leading number
console.log(parseInt("12abc34"));   // 12   — stops at 'a'

parseInt() with Radix (Base)

Always pass the radix (base) as the second argument.

console.log(parseInt("ff",    16)); // 255 — hexadecimal
console.log(parseInt("11",     2)); // 3   — binary
console.log(parseInt("77",     8)); // 63  — octal
console.log(parseInt("42",    10)); // 42  — decimal (always specify!)

parseFloat() — String to Decimal

Parses a string and returns a floating-point number.

console.log(parseFloat("3.14"));      // 3.14
console.log(parseFloat("3.14abc"));   // 3.14 — stops at 'a'
console.log(parseFloat("  3.14  ")); // 3.14 — trims whitespace
console.log(parseFloat("abc"));       // NaN
console.log(parseFloat("3.14.15"));   // 3.14 — stops at second '.'

Number() Constructor — Strict Conversion

Converts a value to a number. Stricter than parseInt/parseFloat.

console.log(Number("42"));       // 42
console.log(Number("3.14"));     // 3.14
console.log(Number("42px"));     // NaN  — doesn't ignore trailing chars
console.log(Number(""));         // 0
console.log(Number(true));       // 1
console.log(Number(false));      // 0
console.log(Number(null));       // 0
console.log(Number(undefined));  // NaN
console.log(Number("  42  "));   // 42   — trims whitespace

Comparison — parseInt vs parseFloat vs Number

let inputs = ["42", "3.14", "42px", "px42", "", "  10  ", true, null];

inputs.forEach(val => {
  console.log(
    `${String(val).padEnd(10)} | parseInt: ${String(parseInt(val)).padEnd(6)} | parseFloat: ${String(parseFloat(val)).padEnd(8)} | Number: ${Number(val)}`
  );
});
// Output:
// 42         | parseInt: 42     | parseFloat: 42       | Number: 42
// 3.14       | parseInt: 3      | parseFloat: 3.14     | Number: 3.14
// 42px       | parseInt: 42     | parseFloat: 42       | Number: NaN
// px42       | parseInt: NaN    | parseFloat: NaN      | Number: NaN
//            | parseInt: NaN    | parseFloat: NaN      | Number: 0
//   10       | parseInt: 10     | parseFloat: 10       | Number: 10
// true       | parseInt: NaN    | parseFloat: NaN      | Number: 1
// null       | parseInt: NaN    | parseFloat: NaN      | Number: 0

Converting Numbers to Strings

toString() — Number to String

let n = 255;

console.log(n.toString());    // "255"    — decimal (default)
console.log(n.toString(2));   // "11111111" — binary
console.log(n.toString(8));   // "377"    — octal
console.log(n.toString(16));  // "ff"     — hexadecimal

// Practical: zero-pad a number
let id = 7;
console.log(id.toString().padStart(4, "0")); // "0007"

toFixed() — Fixed Decimal Places

Returns a string with a specified number of decimal places.

let price = 1234.5678;

console.log(price.toFixed(0)); // "1235"    — no decimals (rounded)
console.log(price.toFixed(2)); // "1234.57" — 2 decimal places
console.log(price.toFixed(4)); // "1234.5678"
console.log(price.toFixed(6)); // "1234.567800" — pads with zeros

// ⚠️ Returns a STRING — convert back if you need a number
console.log(typeof price.toFixed(2));        // "string"
console.log(parseFloat(price.toFixed(2)));   // 1234.57 (number)

toPrecision() — Significant Digits

Returns a string with a specified total number of significant digits.

let n = 123.456;

console.log(n.toPrecision(4)); // "123.5"  — 4 significant digits
console.log(n.toPrecision(5)); // "123.46" — 5 significant digits
console.log(n.toPrecision(7)); // "123.4560"
console.log(n.toPrecision(2)); // "1.2e+2" — scientific notation

let small = 0.000123;
console.log(small.toPrecision(2)); // "0.00012"

toExponential() — Scientific Notation

let n = 1234567;

console.log(n.toExponential());    // "1.234567e+6"
console.log(n.toExponential(2));   // "1.23e+6"
console.log(n.toExponential(4));   // "1.2346e+6"

Number Formatting

toLocaleString() — Human-Readable Format

let amount = 1234567.89;

// Indian format (lakhs/crores)
console.log(amount.toLocaleString("en-IN"));
// "12,34,567.89"

// US format
console.log(amount.toLocaleString("en-US"));
// "1,234,567.89"

// Currency format — Indian Rupee
console.log(amount.toLocaleString("en-IN", {
  style:    "currency",
  currency: "INR",
}));
// "₹12,34,567.89"

// Currency format — US Dollar
console.log(amount.toLocaleString("en-US", {
  style:    "currency",
  currency: "USD",
}));
// "$1,234,567.89"

// Percentage
console.log((0.1875).toLocaleString("en-IN", {
  style:               "percent",
  minimumFractionDigits: 1,
}));
// "18.8%"

Custom Currency Formatter

function formatCurrency(amount, currency = "INR", locale = "en-IN") {
  return amount.toLocaleString(locale, {
    style:                 "currency",
    currency:              currency,
    minimumFractionDigits: 2,
    maximumFractionDigits: 2,
  });
}

console.log(formatCurrency(55000));           // ₹55,000.00
console.log(formatCurrency(1234567.5));       // ₹12,34,567.50
console.log(formatCurrency(99.9, "USD", "en-US")); // $99.90

Safe Number Operations

Check Before Using

function safeParseInt(value, fallback = 0) {
  let parsed = parseInt(value, 10);
  return Number.isNaN(parsed) ? fallback : parsed;
}

function safeParseFloat(value, fallback = 0) {
  let parsed = parseFloat(value);
  return Number.isNaN(parsed) ? fallback : parsed;
}

console.log(safeParseInt("42"));      // 42
console.log(safeParseInt("abc"));     // 0  (fallback)
console.log(safeParseInt("abc", -1)); // -1 (custom fallback)

console.log(safeParseFloat("3.14"));  // 3.14
console.log(safeParseFloat("abc"));   // 0  (fallback)

Check if a String is a Valid Number

function isNumeric(value) {
  return !Number.isNaN(parseFloat(value)) && isFinite(value);
}

console.log(isNumeric("42"));        // true
console.log(isNumeric("3.14"));      // true
console.log(isNumeric("-7"));        // true
console.log(isNumeric("42px"));      // false
console.log(isNumeric("abc"));       // false
console.log(isNumeric(""));          // false
console.log(isNumeric(Infinity));    // false

Real-World Examples

Example 1: Invoice Calculator

function createInvoice(items, taxRate = 18, discountPercent = 0) {
  let subtotal = items.reduce((sum, { price, qty }) => sum + price * qty, 0);
  let discount = parseFloat((subtotal * discountPercent / 100).toFixed(2));
  let taxable  = parseFloat((subtotal - discount).toFixed(2));
  let tax      = parseFloat((taxable * taxRate / 100).toFixed(2));
  let total    = parseFloat((taxable + tax).toFixed(2));

  return { subtotal, discount, taxable, tax, total };
}

let invoice = createInvoice([
  { name: "JavaScript Course", price: 1999, qty: 1 },
  { name: "React Course",      price: 2499, qty: 1 },
  { name: "Node.js Course",    price: 1799, qty: 1 },
], 18, 10);

console.log("=== 🧾 Invoice ===");
console.log(`Subtotal : ${formatCurrency(invoice.subtotal)}`);
console.log(`Discount : -${formatCurrency(invoice.discount)}`);
console.log(`Taxable  : ${formatCurrency(invoice.taxable)}`);
console.log(`GST 18%  : ${formatCurrency(invoice.tax)}`);
console.log(`TOTAL    : ${formatCurrency(invoice.total)}`);

function formatCurrency(n) {
  return n.toLocaleString("en-IN", { style: "currency", currency: "INR" });
}
// Output:
// Subtotal : ₹6,297.00
// Discount : -₹629.70
// Taxable  : ₹5,667.30
// GST 18%  : ₹1,020.11
// TOTAL    : ₹6,687.41

Example 2: Form Input Validator

function validateNumberInput(value, { min, max, integer = false, label = "Value" } = {}) {
  let errors = [];

  // Check if it's a number at all
  if (value === "" || value === null || value === undefined) {
    return { valid: false, errors: [`${label} is required`] };
  }

  let num = Number(value);

  if (Number.isNaN(num)) {
    return { valid: false, errors: [`${label} must be a valid number`] };
  }
  if (!Number.isFinite(num)) {
    errors.push(`${label} must be a finite number`);
  }
  if (integer && !Number.isInteger(num)) {
    errors.push(`${label} must be a whole number`);
  }
  if (min !== undefined && num < min) {
    errors.push(`${label} must be at least ${min}`);
  }
  if (max !== undefined && num > max) {
    errors.push(`${label} must be at most ${max}`);
  }

  return { valid: errors.length === 0, value: num, errors };
}

let tests = [
  ["25",       { min: 18,  max: 65, integer: true,  label: "Age"      }],
  ["15",       { min: 18,  max: 65, integer: true,  label: "Age"      }],
  ["3.14",     { min: 0,   max: 10, integer: false, label: "Rating"   }],
  ["abc",      { min: 0,   max: 10,                 label: "Score"    }],
  ["",         {                                     label: "Quantity" }],
  ["99999",    { min: 0,   max: 1000,                label: "Price"   }],
];

tests.forEach(([val, opts]) => {
  let result = validateNumberInput(val, opts);
  console.log(result.valid
    ? `✅ "${val}" → ${opts.label}: ${result.value}`
    : `❌ "${val}" → ${result.errors.join(", ")}`
  );
});
// Output:
// ✅ "25"    → Age: 25
// ❌ "15"    → Age must be at least 18
// ✅ "3.14"  → Rating: 3.14
// ❌ "abc"   → Score must be a valid number
// ❌ ""      → Quantity is required
// ❌ "99999" → Price must be at most 1000

Example 3: Score Board with Formatting

let players = [
  { name: "Mihir",  score: 9823.5,  wins: 42 },
  { name: "Priya",  score: 11204.0, wins: 58 },
  { name: "Rahul",  score: 7654.25, wins: 31 },
  { name: "Sara",   score: 15000.8, wins: 71 },
  { name: "Arjun",  score: 8901.1,  wins: 45 },
];

let sorted = [...players].sort((a, b) => b.score - a.score);
let total  = players.reduce((s, p) => s + p.score, 0);
let avg    = total / players.length;

console.log("=== 🏆 Leaderboard ===");
sorted.forEach(({ name, score, wins }, i) => {
  let pct = ((score / total) * 100).toFixed(1);
  console.log(
    `${i + 1}. ${name.padEnd(8)} ` +
    `Score: ${score.toLocaleString("en-IN", { minimumFractionDigits: 1 }).padStart(10)} ` +
    `Wins: ${String(wins).padStart(3)} ` +
    `Share: ${pct}%`
  );
});

console.log(`\nAverage Score : ${avg.toLocaleString("en-IN", { maximumFractionDigits: 1 })}`);
console.log(`Total Score   : ${total.toLocaleString("en-IN")}`);
// Output:
// 1. Sara     Score:     15,000.8 Wins:  71 Share: 28.8%
// 2. Priya    Score:     11,204.0 Wins:  58 Share: 21.5%
// 3. Mihir    Score:      9,823.5 Wins:  42 Share: 18.8%
// 4. Arjun    Score:      8,901.1 Wins:  45 Share: 17.1%
// 5. Rahul    Score:      7,654.2 Wins:  31 Share: 14.7%

Example 4: Unit Converter

const conversions = {
  length: {
    kmToMiles:  n => parseFloat((n * 0.621371).toFixed(4)),
    milesToKm:  n => parseFloat((n * 1.60934).toFixed(4)),
    mToFeet:    n => parseFloat((n * 3.28084).toFixed(4)),
    feetToM:    n => parseFloat((n * 0.3048).toFixed(4)),
  },
  weight: {
    kgToLbs:    n => parseFloat((n * 2.20462).toFixed(4)),
    lbsToKg:    n => parseFloat((n * 0.453592).toFixed(4)),
    gToOz:      n => parseFloat((n * 0.035274).toFixed(4)),
  },
  temperature: {
    cToF:       c => parseFloat(((c * 9/5) + 32).toFixed(2)),
    fToC:       f => parseFloat(((f - 32) * 5/9).toFixed(2)),
    cToK:       c => parseFloat((c + 273.15).toFixed(2)),
  },
};

console.log("=== 📏 Unit Converter ===");
console.log(`100 km   = ${conversions.length.kmToMiles(100)} miles`);
console.log(`70 kg    = ${conversions.weight.kgToLbs(70)} lbs`);
console.log(`100°C    = ${conversions.temperature.cToF(100)}°F`);
console.log(`37°C     = ${conversions.temperature.cToF(37)}°F (body temp)`);
console.log(`0°C      = ${conversions.temperature.cToK(0)}K`);
// Output:
// 100 km   = 62.1371 miles
// 70 kg    = 154.3234 lbs
// 100°C    = 212°F
// 37°C     = 98.6°F (body temp)
// 0°C      = 273.15K

Number Methods Cheat Sheet

Method / PropertyWhat it doesExample
Number.isNaN(n)Is it NaN?Number.isNaN(NaN)true
Number.isFinite(n)Is it finite?Number.isFinite(Infinity)false
Number.isInteger(n)Is it whole?Number.isInteger(4.0)true
Number.isSafeInteger(n)Safe for exact math?Number.isSafeInteger(9e15)false
Number.parseInt(s)String to intNumber.parseInt("42px")42
Number.parseFloat(s)String to floatNumber.parseFloat("3.14")3.14
n.toFixed(d)Fixed decimals (string)(3.14159).toFixed(2)"3.14"
n.toPrecision(d)Sig digits (string)(123.4).toPrecision(4)"123.4"
n.toString(base)Number to string(255).toString(16)"ff"
n.toExponential(d)Scientific notation(12345).toExponential(2)"1.23e+4"
n.toLocaleString()Formatted string(1234567).toLocaleString("en-IN")"12,34,567"
Number.MAX_SAFE_INTEGER9007199254740991Largest safe int
Number.EPSILON~2.22e-16Smallest difference
Number.MAX_VALUE~1.8e+308Largest finite number
Number.POSITIVE_INFINITYInfinity
Number.NaNNaN value

Common Mistakes

Mistake 1: Using Global isNaN() Instead of Number.isNaN()

// ❌ Global isNaN() converts the value first — misleading results!
console.log(isNaN("hello"));    // true  — "hello" gets coerced to NaN
console.log(isNaN(undefined));  // true  — undefined gets coerced to NaN
console.log(isNaN(""));         // false — "" gets coerced to 0!

// ✅ Number.isNaN() — no coercion, exact check
console.log(Number.isNaN("hello"));   // false — it's a string, not NaN
console.log(Number.isNaN(undefined)); // false — it's undefined, not NaN
console.log(Number.isNaN(NaN));       // true  ✅

Mistake 2: toFixed() Returns a String

let price = 99.9;

// ❌ toFixed returns a STRING — arithmetic breaks!
let withTax = price.toFixed(2) + 10; // "99.90" + 10 = "99.9010" ❌ (string concat!)

// ✅ Convert back to number first
let withTax2 = parseFloat(price.toFixed(2)) + 10; // 109.9 ✅
let withTax3 = Number(price.toFixed(2)) + 10;     // 109.9 ✅

Mistake 3: Comparing with NaN Directly

let result = parseInt("abc");

// ❌ NaN is never equal to anything — even itself!
console.log(result === NaN);      // false ❌
console.log(result == NaN);       // false ❌
console.log(NaN === NaN);         // false ❌

// ✅ Always use Number.isNaN() to check
console.log(Number.isNaN(result)); // true ✅

Mistake 4: Floating Point in Conditionals

let total = 0.1 + 0.2;

// ❌ Will never be true due to floating point!
if (total === 0.3) {
  console.log("Equal"); // Never runs ❌
}

// ✅ Use a tolerance (epsilon) comparison
if (Math.abs(total - 0.3) < Number.EPSILON) {
  console.log("Equal ✅"); // Works! ✅
}

// ✅ Or round both sides before comparing
if (parseFloat(total.toFixed(2)) === 0.3) {
  console.log("Equal ✅"); // Works! ✅
}

Mistake 5: parseInt Without Radix

// ❌ No radix — behavior can be unexpected with leading zeros
console.log(parseInt("010")); // Could be 8 (octal) in older engines!
console.log(parseInt("0xff")); // 255 — automatically hexadecimal

// ✅ Always specify radix 10 for decimal numbers
console.log(parseInt("010", 10)); // 10 ✅
console.log(parseInt("42",  10)); // 42 ✅

Practical Exercise

Create a file called number-object.js:

// 🎯 Number Object Practice

// 1. Number type detective
console.log("=== 🔍 Number Type Checks ===");
let values = [42, 3.14, NaN, Infinity, -Infinity, "42", null, undefined, 0, -0];

values.forEach(v => {
  console.log(
    `${String(v).padEnd(12)} | ` +
    `isNaN: ${String(Number.isNaN(v)).padEnd(6)} | ` +
    `isFinite: ${String(Number.isFinite(v)).padEnd(6)} | ` +
    `isInteger: ${String(Number.isInteger(v)).padEnd(6)} | ` +
    `isSafeInt: ${Number.isSafeInteger(v)}`
  );
});


// 2. String-to-number parser
console.log("\n=== 🔄 Parsing Comparison ===");
let inputs = ["42", "3.14", "  100  ", "42px", "px42", "0xFF", "3.14.15", ""];

inputs.forEach(input => {
  let pi = parseInt(input, 10);
  let pf = parseFloat(input);
  let n  = Number(input);

  console.log(
    `"${input}".padEnd(12) → ` +
    `parseInt: ${String(pi).padEnd(8)} ` +
    `parseFloat: ${String(pf).padEnd(8)} ` +
    `Number: ${n}`
  );
});


// 3. Currency formatter
console.log("\n=== 💰 Currency Formatter ===");
let amounts = [1000, 12345.678, 9999999, 0.5, 100000000];

amounts.forEach(amount => {
  let inr = amount.toLocaleString("en-IN", { style: "currency", currency: "INR", maximumFractionDigits: 2 });
  let usd = amount.toLocaleString("en-US", { style: "currency", currency: "USD", maximumFractionDigits: 2 });
  console.log(`${String(amount).padEnd(14)} → INR: ${inr.padEnd(18)} USD: ${usd}`);
});


// 4. Safe math utility
console.log("\n=== 🛡️ Safe Math ===");
function safeDivide(a, b, fallback = 0) {
  if (!Number.isFinite(a) || !Number.isFinite(b)) return fallback;
  if (b === 0) return fallback;
  return parseFloat((a / b).toFixed(10));
}

function safePercentage(part, total, decimals = 1) {
  if (total === 0) return "N/A";
  return parseFloat(((part / total) * 100).toFixed(decimals)) + "%";
}

console.log(`10 / 2    = ${safeDivide(10, 2)}`);
console.log(`10 / 0    = ${safeDivide(10, 0)}`);
console.log(`NaN / 5   = ${safeDivide(NaN, 5)}`);
console.log(`Inf / 2   = ${safeDivide(Infinity, 2)}`);

console.log(`45/200    = ${safePercentage(45, 200)}`);
console.log(`0/0       = ${safePercentage(0, 0)}`);
console.log(`1/3       = ${safePercentage(1, 3, 2)}`);

Run it:

node number-object.js

Expected Output:

=== 🔍 Number Type Checks ===
42           | isNaN: false  | isFinite: true   | isInteger: true   | isSafeInt: true
3.14         | isNaN: false  | isFinite: true   | isInteger: false  | isSafeInt: false
NaN          | isNaN: true   | isFinite: false  | isInteger: false  | isSafeInt: false
Infinity     | isNaN: false  | isFinite: false  | isInteger: false  | isSafeInt: false
...

=== 💰 Currency Formatter ===
1000INR: ₹1,000.00       USD: $1,000.00
12345.678INR: ₹12,345.68      USD: $12,345.68
9999999INR: ₹99,99,999.00   USD: $9,999,999.00
...

=== 🛡️ Safe Math ===
10 / 2    = 5
10 / 0    = 0
NaN / 5   = 0
Inf / 2   = 0
45/200    = 22.5%
0/0       = N/A
1/3       = 33.33%

Key Takeaways

Congratulations! 🎉 You now have a deep, complete understanding of numbers in JavaScript.

All numbers are float64 — no separate int type. This causes the floating point issue (0.1 + 0.2 !== 0.3).

Fix float issuesparseFloat(n.toFixed(2)), work in integers (paise/cents), or use Number.EPSILON.

NaN — results from invalid math. Use Number.isNaN() — never === NaN or global isNaN().

Parsing:

  • parseInt(str, 10) — string to integer, ignores trailing chars
  • parseFloat(str) — string to decimal
  • Number(val) — strict, returns NaN for mixed strings

Formatting:

  • toFixed(d) → fixed decimals as string
  • toPrecision(d) → significant digits as string
  • toLocaleString(locale, opts) → human-readable with currency/percent support

Checks:

  • Number.isNaN() — is it NaN?
  • Number.isFinite() — is it finite?
  • Number.isInteger() — is it whole?
  • Number.isSafeInteger() — can it be represented exactly?

Always specify radix 10 when using parseInt().


Best Practices

  1. ✅ Always use Number.isNaN() — never global isNaN() or === NaN
  2. ✅ Always pass radix 10 to parseInt()parseInt(val, 10)
  3. ✅ Remember toFixed() returns a string — wrap in parseFloat() if you need a number
  4. ✅ Use toLocaleString() for all user-facing number and currency display
  5. ✅ Fix floating-point comparisons with Number.EPSILON or by rounding both sides
  6. ✅ For financial calculations, work in smallest units (paise/cents) to avoid float issues
  7. ✅ Use Number.isFinite() to guard against Infinity and NaN before doing math
  8. ✅ Build safeParseInt and safeParseFloat utilities in your projects — use them everywhere

What's Next?

Great work! 🎉 You now understand numbers in JavaScript at a deep level.

Next up, the final topic in the JavaScript Objects section:

Boolean → — truthy and falsy values, logical operators, type coercion, and everything about booleans in JavaScript!

Let's finish strong! 💪