JavaScript Number Tricks Every Developer Should Know
Numbers in JS are weird. Here's how to handle them correctly.
The Basics (That Everyone Gets Wrong)
// JS has only ONE number type: IEEE 754 double-precision float
typeof 42; // "number"
typeof 3.14; // "number"
typeof NaN; // "number" (!)
typeof Infinity; // "number" (!)
// Integer safety limit
Number.MAX_SAFE_INTEGER // 9007199254740991 (~16 digits)
Number.MIN_SAFE_INTEGER // -9007199254740991
Number.isSafeInteger(9007199254740992) // false — beyond safe range!
// Common gotchas:
0.1 + 0.2 === 0.3 // false! (0.30000000000000004)
0.1 + 0.2 // 0.30000000000000004
Formatting Numbers
const price = 1234.5678;
const users = 9876543;
const rating = 4.8523;
// Currency
price.toLocaleString('en-US', { style: 'currency', currency: 'USD' });
// "$1,234.57"
price.toLocaleString('de-DE', { style: 'currency', currency: 'EUR' });
// "1.234,57 €"
// Compact large numbers
users.toLocaleString('en-US', { notation: 'compact' });
// "988K"
users.toLocaleString('en-US', { notation: 'compact', compactDisplay: 'long' });
// "988 thousand"
// Percentage
(rating / 5).toLocaleString('en-US', { style: 'percent', minimumFractionDigits: 1 });
// "97.0%"
// Fixed decimal places
price.toFixed(2); // "1234.57"
price.toFixed(0); // "1235"
// With commas (locale-aware)
users.toLocaleString('en-US'); // "987,654"
users.toLocaleString('de-DE'); // "987.654"
Math Operations You Actually Need
// Random integer in range [min, max]
function randomInt(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
randomInt(1, 6); // Dice roll: 1-6
randomInt(0, 100); // Percentage: 0-100
// Round to specific precision
function roundTo(num, decimals) {
const factor = Math.pow(10, decimals);
return Math.round(num * factor) / factor;
}
roundTo(3.14159, 2); // 3.14
roundTo(99.956, 1); // 99.96
// Clamp value between min and max
function clamp(value, min, max) {
return Math.min(Math.max(value, min), max);
}
clamp(-5, 0, 100); // 0
clamp(150, 0, 100); // 100
clamp(50, 0, 100); // 50
// Percentage calculation
function percentage(part, total) {
return (part / total) * 100;
}
percentage(30, 200); // 15
percentage(7, 28); // 25
// Linear interpolation (lerp)
function lerp(start, end, t) {
return start + (end - start) * t;
}
lerp(0, 100, 0.5); // 50
lerp(10, 20, 0.75); // 17.5
// Check if number is between two values (inclusive)
function isBetween(n, a, b) {
return n >= Math.min(a, b) && n <= Math.max(a, b);
}
isBetween(5, 1, 10); // true
isBetween(15, 1, 10); // false
Handling Money (The Right Way)
// ❌ NEVER use floating point for money!
const total = 0.1 + 0.2 + 0.1 + 0.1 + 0.1;
total === 0.5; // false! (0.5000000000000001)
// ✅ Option 1: Work in cents (integers)
const priceCents = 1999; // $19.99
const taxCents = Math.round(priceCents * 0.08); // 160
const totalCents = priceCents + taxCents; // 2159
const display = (totalCents / 100).toFixed(2); // "21.59"
// ✅ Option 2: Use a library (dinero.js, currency.js)
import Dinero from 'dinero.js';
const price = Dinero({ amount: 1999, currency: 'USD' });
const tax = price.percentage(8);
const total = price.add(tax);
total.toFormat(); // "$21.59"
total.getAmount(); // 2159 (integer cents!)
Number Validation
// Is it actually a number?
Number.isNaN(NaN); // true
Number.isNaN('hello'); // false (unlike global isNaN!)
isNaN('hello'); // true (coerces to number first — confusing!)
Number.isFinite(42); // true
Number.isFinite(Infinity); // false
Number.isFinite(NaN); // false
// Parse safely
parseInt('42px', 10); // 42 (stops at non-digit)
parseFloat('3.14rem'); // 3.14
parseInt('hello', 10); // NaN
Number('123'); // 123
Number('123abc'); // NaN
// Safe parsing utility
function parseNumber(val, fallback = 0) {
const num = Number(val);
return Number.isNaN(num) ? fallback : num;
}
parseNumber('42'); // 42
parseNumber('invalid'); // 0 (fallback)
parseNumber('', -1); // -1 (custom fallback)
BigInt (For Really Big Numbers)
// Regular numbers can't handle this:
Number.MAX_SAFE_INTEGER + 1 === Number.MAX_SAFE_INTEGER + 2; // true!
// BigInt to the rescue:
const big = 9007199254740993n; // Note the 'n' suffix
big + 1n === big + 2n; // false (correct!)
// Practical use: Database IDs, timestamps, crypto
const userId = 38429175839284759283n;
const timestamp = Date.now() * 1000000n + process.hrtime.bigint();
// Can't mix with regular numbers:
big + 1; // TypeError!
big + 1n; // OK
// Convert back and forth
BigInt(Number.MAX_SAFE_INTEGER); // 9007199254740991n
Number(9007199254740993n); // 9007199254740993 (if within safe range)
Unit Conversions
// Bytes to human-readable
function formatBytes(bytes, decimals = 2) {
if (bytes === 0) return '0 Bytes';
const k = 1024;
const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'];
const i = Math.floor(Math.log(bytes) / Math.log(k));
return parseFloat((bytes / Math.pow(k, i)).toFixed(decimals)) + ' ' + sizes[i];
}
formatBytes(0); // "0 Bytes"
formatBytes(1024); // "1 KB"
formatBytes(1048576); // "1 MB"
formatBytes(1073741824); // "1 GB"
formatBytes(15600000); // "14.88 MB"
// Milliseconds to readable duration
function formatDuration(ms) {
const seconds = Math.floor(ms / 1000);
const minutes = Math.floor(seconds / 60);
const hours = Math.floor(minutes / 60);
const days = Math.floor(hours / 24);
if (days > 0) return `${days}d ${hours % 24}h ${minutes % 60}m`;
if (hours > 0) return `${hours}h ${minutes % 60}m ${seconds % 60}s`;
if (minutes > 0) return `${minutes}m ${seconds % 60}s`;
return `${seconds}s`;
}
formatDuration(1000); // "1s"
formatDuration(65000); // "1m 5s"
formatDuration(3661000); // "1h 1m 1s"
formatDuration(90000000); // "1d 1h 0m"
Quick Reference
| Task | Code | Result |
|---|---|---|
| Format currency | (1234.56).toLocaleString('en-US',{style:'currency'}) |
"$1,234.57" |
| Round to N places | Math.round(x * 100) / 100 |
2 decimals |
| Random int | Math.floor(Math.random() * (max-min+1)) + min |
Range |
| Clamp | Math.min(Math.max(v, min), max) |
In range |
| Safe parse |
Number(x) or parseInt
|
Number or NaN |
| Is integer? | Number.isInteger(42) |
boolean |
| Is safe int? | Number.isSafeInteger(x) |
boolean |
| To fixed | x.toFixed(2) |
String |
| With commas | x.toLocaleString() |
"1,234,567" |
| Percentage | `((part/total)*100).toFixed(1) + '%' | "25.0%" |
What's your favorite number trick? Share it below!
Follow @armorbreak for more JavaScript content.
Top comments (0)