Remote Income Hub

How to Convert a String to a Number in JavaScript

Converting strings to numbers is something every JavaScript developer does constantly. User input always comes in as a string. API responses sometimes return numbers wrapped in quotes. Form fields give you text even when the user typed a digit.

JavaScript gives you several ways to make the conversion — each with different behavior, different edge cases, and different ideal use cases. Knowing which one to reach for in which situation saves you from subtle bugs that are genuinely hard to track down.

The Main Methods

There are four common ways to convert a string to a number in JavaScript:

Each one handles edge cases differently. Let’s go through all of them.

Number()

Number() is the most explicit and readable approach. Pass it a string and it returns the numeric equivalent:

console.log(Number("42"));       // 42
console.log(Number("3.14"));     // 3.14
console.log(Number("0"));        // 0
console.log(Number(""));         // 0
console.log(Number("  42  "));   // 42  (trims whitespace)
console.log(Number("42px"));     // NaN
console.log(Number("hello"));    // NaN
console.log(Number(true));       // 1
console.log(Number(false));      // 0
console.log(Number(null));       // 0
console.log(Number(undefined));  // NaN

Key behaviors to note:

Number() is the safest general-purpose conversion when you expect a clean numeric string. It fails loudly with NaN when the input is not a valid number, which makes it easy to detect bad input.

parseInt()

parseInt() parses a string and returns an integer. Unlike Number(), it reads from left to right and stops at the first non-numeric character:

console.log(parseInt("42"));      // 42
console.log(parseInt("42.9"));    // 42  (truncates decimal)
console.log(parseInt("42px"));    // 42  (stops at "p")
console.log(parseInt("px42"));    // NaN (starts with non-numeric)
console.log(parseInt("3.14"));    // 3
console.log(parseInt(""));        // NaN
console.log(parseInt("0xFF", 16)); // 255 (hex with radix)

Always pass a radix (base) as the second argument. Without it, parseInt() guesses the base from the string format, which can lead to unexpected results:

// Always specify base 10 for decimal numbers
console.log(parseInt("08", 10));  // 8
console.log(parseInt("42", 10));  // 42

parseInt() is the right choice when you need a whole number and your input might include units or extra characters after the digits — like CSS values ("24px", "100%") or user-entered measurements.

parseFloat()

parseFloat() works like parseInt() but preserves decimal values:

console.log(parseFloat("3.14"));     // 3.14
console.log(parseFloat("3.14abc"));  // 3.14  (stops at "a")
console.log(parseFloat("42"));       // 42
console.log(parseFloat(".5"));       // 0.5
console.log(parseFloat("abc"));      // NaN
console.log(parseFloat(""));         // NaN

Unlike parseInt(), parseFloat() does not take a radix argument — it always parses as base 10 decimal.

Use parseFloat() when you need to preserve decimal precision and your input might have trailing non-numeric characters.

The Unary + Operator

Placing a + before a string converts it to a number. It behaves exactly like Number() but is more compact:

console.log(+"42");       // 42
console.log(+"3.14");     // 3.14
console.log(+"");         // 0
console.log(+"42px");     // NaN
console.log(+"hello");    // NaN
console.log(+true);       // 1
console.log(+null);       // 0
console.log(+undefined);  // NaN

The unary + is popular in compact code and one-liners. The downside is readability — +"42" is less obvious than Number("42") to developers who are not expecting it.

Use it when brevity matters and the conversion is obvious from context. Prefer Number() when clarity is more important.

Checking for NaN After Conversion

Any conversion that fails returns NaN — “Not a Number.” You can not compare NaN directly because NaN !== NaN in JavaScript:

const result = Number("hello");

// Wrong — always false
console.log(result === NaN); // false

// Correct
console.log(isNaN(result));        // true
console.log(Number.isNaN(result)); // true

Number.isNaN() is the more reliable check. Unlike the global isNaN(), it does not coerce its argument before checking — so it only returns true for actual NaN values, not for strings that would convert to NaN:

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

console.log(isNaN(NaN));            // true
console.log(Number.isNaN(NaN));     // true

For checking whether a conversion produced a valid number, this pattern works cleanly:

function toNumber(str) {
  const num = Number(str);
  if (Number.isNaN(num)) {
    return null; // or throw, or return a default
  }
  return num;
}

console.log(toNumber("42"));     // 42
console.log(toNumber("hello"));  // null
console.log(toNumber("3.14"));   // 3.14

Real-World Example: Converting Form Input

Form values are always strings. Here is a common pattern for converting and validating user input:

const input = document.getElementById("price").value; // "24.99"

const price = parseFloat(input);

if (Number.isNaN(price) || price < 0) {
  console.error("Invalid price entered.");
} else {
  console.log(`Price: $${price.toFixed(2)}`); // "Price: $24.99"
}

parseFloat() handles decimal user input. The Number.isNaN() check catches invalid entries. .toFixed(2) formats the output for display.

Comparing All Four Methods Side by Side

const inputs = ["42", "3.14", "42px", "", " 99 ", "hello", null, undefined];

inputs.forEach(val => {
  console.log(`Input: ${JSON.stringify(val)}`);
  console.log(`  Number():     ${Number(val)}`);
  console.log(`  parseInt():   ${parseInt(val, 10)}`);
  console.log(`  parseFloat(): ${parseFloat(val)}`);
  console.log(`  +val:         ${+val}`);
  console.log("---");
});

Running this gives you a clear picture of how each method handles every edge case. The key differences:

InputNumber()parseInt()parseFloat()+val
“42”42424242
“3.14”3.1433.143.14
“42px”NaN4242NaN
“”0NaNNaN0
” 99 “99999999
“hello”NaNNaNNaNNaN
null0NaNNaN0
undefinedNaNNaNNaNNaN

Which Method Should You Use?

Number() — Default choice for clean numeric strings. Clear, explicit, strict about what it accepts.

parseInt(val, 10) — When you need a whole number and input may have trailing characters like units or labels.

parseFloat() — When you need decimal precision and input may have trailing non-numeric characters.

+val — Same as Number() but more compact. Use when brevity is preferred in a context where the intent is clear.

Tips for String-to-Number Conversions

Always validate after converting. Never assume the conversion succeeded. Check for NaN before using the result in calculations.

Use parseInt() with a radix. Always pass 10 as the second argument unless you are intentionally parsing hex, octal, or binary.

Do not use parseFloat() for currency math. Floating-point arithmetic has precision issues. Use Number() with Number.EPSILON rounding for financial calculations.

Trim whitespace before converting. Most methods handle leading and trailing spaces, but explicit trimming makes intent clear: Number(str.trim()).

Do not use new Number(). The constructor form creates a Number object, not a primitive. typeof new Number("42") returns "object", not "number", which breaks most comparisons.

// Wrong
const n = new Number("42");
console.log(typeof n); // "object"
console.log(n === 42); // false

// Correct
const n = Number("42");
console.log(typeof n); // "number"
console.log(n === 42); // true

Converting strings to numbers in JavaScript comes down to choosing the right tool for your input. Number() and the unary + are strict — they return NaN for anything with non-numeric characters. parseInt() and parseFloat() are lenient — they parse as far as they can and stop.

Always check for NaN after conversion. Always specify the radix with parseInt(). And reach for Number() as your default unless there is a specific reason to use one of the others.

Exit mobile version