DEV Community

Alex Chen
Alex Chen

Posted on

JavaScript Number Tricks Every Developer Should Know

JavaScript Number Tricks Every Developer Should Know

These aren't math puzzles. These are practical tricks I use in real code.

1. Safe Integer Parsing

// ❌ Common mistakes
parseInt('123abc')       // 123 (ignores trailing chars)
parseInt('abc')          // NaN (no error message)
parseInt('12.5')         // 12 (truncates decimal!)
parseInt('0xFF')         // 255 (parses hex!)

// ✅ Use Number() or unary plus
Number('123')            // 123
Number('123abc')         // NaN
Number('12.5')           // 12.5
+'123'                   // 123 (unary plus)

// ✅ Always validate with Number.isFinite()
function safeParseInt(str, fallback = 0) {
  const num = Number(str);
  return Number.isFinite(num) ? Math.floor(num) : fallback;
}

safeParseInt('42')       // 42
safeParseInt('abc')      // 0 (fallback)
safeParseInt('12.9')     // 12
safeParseInt('')         // 0 (fallback)
Enter fullscreen mode Exit fullscreen mode

2. Floating Point Workarounds

// ❌ Floating point gotchas
0.1 + 0.2              // 0.30000000000000004 (!)
0.1 + 0.2 === 0.3      // false (!!)
9007199254740992 === 9007199254740993  // true (!!!)

// ✅ For money: use integers (cents)
const price = 1299; // $12.99 in cents
const total = price * 3; // 3897 cents = $38.97
console.log('$' + (total / 100).toFixed(2)); // "$38.97"

// ✅ For comparisons: use epsilon
function approxEqual(a, b, epsilon = 1e-10) {
  return Math.abs(a - b) < epsilon;
}

approxEqual(0.1 + 0.2, 0.3)  // true
approxEqual(0.1 + 0.2, 0.3, 0)  // false

// ✅ For formatting: toFixed()
(0.1 + 0.2).toFixed(2)  // "0.30"
parseFloat((0.1 + 0.2).toFixed(2))  // 0.3
Enter fullscreen mode Exit fullscreen mode

3. Random Number Utilities

// Random integer in range [min, max] (inclusive)
function randomInt(min, max) {
  return Math.floor(Math.random() * (max - min + 1)) + min;
}

randomInt(1, 6)    // Dice roll: 1-6
randomInt(0, 255)  // Color component: 0-255

// Random element from array
function randomPick(arr) {
  return arr[Math.floor(Math.random() * arr.length)];
}

const colors = ['red', 'green', 'blue'];
randomPick(colors)  // Random color

// Shuffle array (Fisher-Yates)
function shuffle(arr) {
  const a = [...arr]; // Don't mutate original
  for (let i = a.length - 1; i > 0; i--) {
    const j = Math.floor(Math.random() * (i + 1));
    [a[i], a[j]] = [a[j], a[i]];
  }
  return a;
}

shuffle([1, 2, 3, 4, 5])  // [3, 1, 5, 2, 4]

// Random hex color
function randomColor() {
  return '#' + Math.floor(Math.random() * 16777215).toString(16).padStart(6, '0');
}
randomColor()  // "#3f8a2c"

// Random ID (simple, not crypto-secure)
function randomId(length = 8) {
  return Math.random().toString(36).substring(2, 2 + length);
}
randomId()  // "x7b2k9f1"
randomId(12)  // "a3f8k2j9d1x4"
Enter fullscreen mode Exit fullscreen mode

4. Number Formatting

// Currency
(1234567.89).toLocaleString('en-US', { 
  style: 'currency', 
  currency: 'USD' 
})  // "$1,234,567.89"

// Compact numbers (1.2K, 3.5M, 1.1B)
function compact(num) {
  return new Intl.NumberFormat('en', { 
    notation: 'compact',
    maximumFractionDigits: 1 
  }).format(num);
}

compact(1500)     // "1.5K"
compact(3500000)  // "3.5M"
compact(1100000000) // "1.1B"

// Percentage
(0.856).toLocaleString('en-US', {
  style: 'percent',
  maximumFractionDigits: 1
})  // "85.6%"

// With commas
(1234567).toLocaleString()  // "1,234,567"
(1234567.891).toLocaleString(undefined, {
  maximumFractionDigits: 2
})  // "1,234,567.89"

// Ordinal (1st, 2nd, 3rd, 4th)
function ordinal(n) {
  const s = ['th', 'st', 'nd', 'rd'];
  const v = n % 100;
  return n + (s[(v - 20) % 10] || s[v] || s[0]);
}

ordinal(1)   // "1st"
ordinal(2)   // "2nd"
ordinal(3)   // "3rd"
ordinal(4)   // "4th"
ordinal(11)  // "11th"
ordinal(21)  // "21st"
ordinal(101) // "101st"
Enter fullscreen mode Exit fullscreen mode

5. Math Shortcuts

// Clamp value between min and max
function clamp(val, min, max) {
  return Math.min(Math.max(val, min), max);
}

clamp(5, 0, 10)    // 5
clamp(-3, 0, 10)   // 0
clamp(15, 0, 10)   // 10

// Distance between two numbers
const distance = Math.abs(a - b);

// Map value from one range to another
function mapRange(value, inMin, inMax, outMin, outMax) {
  return ((value - inMin) * (outMax - outMin)) / (inMax - inMin) + outMin;
}

mapRange(5, 0, 10, 0, 100)    // 50
mapRange(0, 0, 10, 32, 212)   // 32 (Celsius to Fahrenheit start)

// Lerp (linear interpolation)
function lerp(start, end, t) {
  return start + (end - start) * t;
}

lerp(0, 100, 0.5)   // 50
lerp(0, 100, 0.25)  // 25

// Round to N decimal places
function roundTo(num, decimals = 2) {
  const factor = 10 ** decimals;
  return Math.round(num * factor) / factor;
}

roundTo(3.14159, 2)  // 3.14
roundTo(3.14159, 4)  // 3.1416

// Is number between two values?
function between(num, min, max) {
  return num > min && num < max;
}

between(5, 0, 10)   // true
between(0, 0, 10)   // false (exclusive)
between(10, 0, 10)  // false (exclusive)
Enter fullscreen mode Exit fullscreen mode

6. Bitwise Tricks

// Check if number is even/odd (faster than % 2)
num & 1   // 0 = even, 1 = odd
5 & 1     // 1 (odd)
4 & 1     // 0 (even)

// Swap two numbers without temp variable
let a = 10, b = 20;
a ^= b; b ^= a; a ^= b;
// a = 20, b = 10

// Floor a positive number (faster than Math.floor)
~~3.7        // 3
~~-3.7       // -3 (Note: NOT the same as Math.floor for negatives!)

// Check if number is a power of 2
function isPowerOf2(n) {
  return n > 0 && (n & (n - 1)) === 0;
}

isPowerOf2(4)   // true
isPowerOf2(8)   // true
isPowerOf2(6)   // false

// Fast multiply by 2 (left shift)
5 << 1    // 10
10 << 2   // 40

// Fast divide by 2 (right shift)
10 >> 1   // 5
20 >> 2   // 5
Enter fullscreen mode Exit fullscreen mode

7. Number Validation

// Is it actually a number?
Number.isFinite(42)         // true
Number.isFinite(Infinity)   // false
Number.isFinite(NaN)        // false
Number.isFinite('42')       // false (string!)
Number.isFinite(null)       // false

// vs typeof (less reliable)
typeof 42        // 'number'
typeof NaN       // 'number' (!!)
typeof Infinity  // 'number'

// Is it a safe integer? (within ±2^53)
Number.isSafeInteger(42)                    // true
Number.isSafeInteger(9007199254740992)      // true (max safe int)
Number.isSafeInteger(9007199254740992 + 1)  // false (!)
Number.isSafeInteger(0.5)                   // false (not integer)

// Is it a positive number?
function isPositiveNumber(val) {
  return typeof val === 'number' && Number.isFinite(val) && val > 0;
}

isPositiveNumber(42)      // true
isPositiveNumber(-1)      // false
isPositiveNumber(0)       // false
isPositiveNumber('42')    // false
isPositiveNumber(NaN)     // false
Enter fullscreen mode Exit fullscreen mode

8. Performance Tips

// ❌ Slow
Math.floor(x)     // Function call overhead
parseInt(x)       // Even slower (parsing logic)

// ✅ Faster (for positive numbers)
~~x               // Bitwise NOT NOT
x | 0             // Bitwise OR
x >> 0            // Bitwise right shift

// But be careful:
~~2147483647       // 2147483647 (OK)
~~2147483648       // -2147483648 (overflow! 32-bit limit)

// For most cases, Math.trunc() is the safest fast option
Math.trunc(4.9)   // 4
Math.trunc(-4.9)  // -4
Enter fullscreen mode Exit fullscreen mode

What number tricks do you use? Share them below!

Follow @armorbreak for more JavaScript content.

Top comments (0)