Historical Context & Motivation
Every programming language needs a way to handle situations where a calculation goes wrong—like dividing zero by zero, or trying to multiply a word by a number. In mathematics, these operations are simply "undefined," but a running computer program can't just stop and shrug. It needs a value to place in memory so execution can continue. The concept of NaN (short for Not-a-Number) was created to fill exactly that role.
At the same time, web pages constantly receive data as text—from form fields, URLs, and server responses. A user typing "42" into a text box produces a string, not an actual number. JavaScript needed built-in tools—parseInt and parseFloat—to convert those text strings into numbers the language can do math with.
parseInt() and parseFloat() for parsing user input.isNaN() function, giving developers a standard way to check whether a value is NaN.Number.isNaN(), a stricter check that fixes quirks in the original isNaN() function, making NaN detection more reliable.The central question this lesson addresses is straightforward: when JavaScript encounters text that looks like a number—or an operation that produces no valid numeric result—how do you detect it, handle it, and convert it safely? Mastering these tools is essential for writing programs that don't crash or produce mysterious bugs when real-world data isn't perfectly clean.
Core Principles & Definitions
Before diving into code, let's establish the foundational ideas behind NaN and number parsing. These concepts show up constantly in real JavaScript programs, so understanding them clearly now will save you many hours of debugging later.
NaN — Not-a-Number
typeof NaN returns "number"—it's technically a number type that signals 'something went wrong.'NaN Is Never Equal to Itself
NaN === NaN returns false. This is the only value in JavaScript (and in IEEE 754) that is not equal to itself. You must use isNaN() or Number.isNaN() to test for it.parseInt() — Parse to Integer
parseFloat() — Parse to Decimal
parseInt() but also recognizes a decimal point, so it can return numbers with fractional parts like 3.14. It ignores trailing non-numeric characters just like parseInt().The Radix Parameter
parseInt() accepts an optional second argument called the radix (base). Always pass 10 for decimal numbers to avoid unexpected behavior with strings that start with "0" or "0x".isNaN() or Number.isNaN()) to detect it and decide what to do next.Visual Explanation — How Parsing Works
The diagram below shows how parseInt() and parseFloat() process a string character by character from left to right. Understanding this left-to-right scanning behavior is the key to predicting what these functions return.
parseFloat() also accepts the decimal point.Notice the critical pattern: both functions are tolerant of trailing junk characters. The string "42px" successfully yields 42 because the parser grabs the leading digits and ignores the rest. However, if the very first character isn't a digit (or a sign like + or -), there are no digits to collect, and the result is NaN.
How It Works — NaN Detection & Parsing Rules
Operations That Produce NaN
JavaScript produces NaN in several predictable situations. Attempting math with non-numeric values, such as "hello" * 3, returns NaN. Indeterminate arithmetic like 0 / 0 also yields NaN. And calling parseInt() or parseFloat() on a string with no leading digits returns NaN as well. Once NaN appears in a calculation, it's "contagious"—any further math with NaN produces NaN.
Detecting NaN: Two Functions
isNaN() function first coerces its argument to a number, then checks if the result is NaN. This means isNaN("hello") returns true because Number("hello") is NaN. This can be confusing because "hello" isn't literally the NaN value—it's a string.Number.isNaN() does no type coercion. It returns true only when the value is already the NaN value. So Number.isNaN("hello") returns false because the string "hello" is not the numeric value NaN.parseInt() Syntax
10 for normal decimal parsing."1.5e3" → 1500).Detailed Breakdown — Parsing Results at a Glance
The following table shows what different inputs produce when passed through parseInt(), parseFloat(), and Number(). Studying these examples side by side reveals the subtle differences between the three approaches. Pay special attention to how each one handles strings with mixed content.
| Input | parseInt(input, 10) | parseFloat(input) | Number(input) |
|---|---|---|---|
"42" | 42 | 42 | 42 |
"3.14" | 3 | 3.14 | 3.14 |
"42px" | 42 | 42 | NaN |
"$99.50" | NaN | NaN | NaN |
" 7 " | 7 | 7 | 7 |
"" | NaN | NaN | 0 |
"0xFF" | 255 | 0 | 255 |
true | NaN | NaN | 1 |
"px" or "kg", use parseFloat or parseInt. If the string should be purely numeric, Number() is the strictest option.Worked Example — Parsing User Input
Imagine you're building a simple web app that calculates the total cost of items. The user types a price into a text field, and your code receives it as a string. Let's walk through parsing and validating that input step by step.
"19.99" into a form field. In JavaScript, the value from an HTML input element is always a string, even if it looks like a number. We store it in a variable:
let userInput = "19.99";"19.99"parseFloat() rather than parseInt() (which would chop off the cents).
let price = parseFloat(userInput);
The parser reads 1, 9, ., 9, 9 and converts them into the number 19.99.19.99"free", parseFloat() would have returned NaN.
if (isNaN(price)) {
console.log("Please enter a valid number.");
} else {
console.log("Price accepted: $" + price);
}"Price accepted: $19.99"let quantity = parseInt("3", 10);
let total = price * quantity;
Notice we used parseInt() with radix 10 for the quantity because it's always a whole number.59.97"19.99 dollars"? Because parseFloat() ignores trailing text, it would still return 19.99. But Number("19.99 dollars") would return NaN because Number() demands the entire string be a valid number. Choose the function that matches how strict you need to be.parseFloat("19.99 dollars") → 19.99 (tolerant) vs. Number("19.99 dollars") → NaN (strict)Strengths, Pitfalls & Comparisons
Each number-conversion approach in JavaScript has distinct advantages and gotchas. The table below compares them so you can make informed choices in your own code.
| Feature | parseInt(s, 10) | parseFloat(s) | Number(s) |
|---|---|---|---|
| Handles trailing text | Yes — ignores non-digit suffix | Yes — ignores non-numeric suffix | No — returns NaN |
| Returns decimals | No — truncates to integer | Yes | Yes |
| Accepts radix | Yes (2–36) | No (always base 10) | Hex strings auto-detected |
| Empty string "" | NaN | NaN | 0 (surprising!) |
| Boolean true | NaN | NaN | 1 |
| Best use case | Extracting integers from messy strings (CSS values, IDs) | Extracting decimal numbers from strings with units | Strict, full-string conversion |
parseInt() can produce unexpected results. In older JavaScript engines, parseInt("08") was treated as octal (base 8) and returned 0. Modern engines default to base 10, but always writing parseInt("08", 10) makes your intention clear and keeps your code safe across all environments.parseInt() and parseFloat() like a metal detector scanning a beach—they pick up the first metallic object (digits) they find and ignore the sand (non-numeric characters) after it. Number() is more like airport security: everything in the string must pass inspection, or the whole thing gets rejected as NaN.Connection to Advanced Concepts
The parsing and NaN-handling skills you've learned here form the foundation for more advanced data processing patterns in JavaScript. As you move into topics like form validation, API data handling, and TypeScript, these ideas scale up significantly.
| This Lesson (Intro) | Advanced Topic |
|---|---|
isNaN() and Number.isNaN() | Defensive programming patterns: null checks, optional chaining (?.), and nullish coalescing (??) |
parseInt() / parseFloat() | Parsing JSON from APIs: JSON.parse() with custom reviver functions for type-safe data handling |
| Type coercion quirks | TypeScript's static type system eliminates many coercion bugs at compile time by enforcing explicit type annotations |
| Basic input validation | Regular expressions (RegExp) for complex pattern matching and input sanitization |
As your projects grow more complex, you'll encounter data coming from databases, third-party APIs, and user inputs that can be wildly unpredictable. The habit of always validating and parsing before computing is one of the most important defensive programming skills you can develop. Every senior developer you'll meet will tell you: never trust incoming data—always check it first.
Practice Problems
Test your understanding with these five problems. They progress from basic recall to critical thinking. Try to answer each one before reading the solution.
NaN === NaN return false in JavaScript? What function should you use instead to check if a value is NaN?parseInt("100px", 10)
b) parseFloat("7.5em")
c) parseInt("abc", 10)isNaN("hello") and Number.isNaN("hello"). What does each return, and why?"72°F" into a text field. Write a short JavaScript code snippet that extracts the number 72, checks if parsing succeeded, and if so, converts it to Celsius using the formula C = (F − 32) × 5 / 9. If parsing fails, log an error message.let x = parseInt("", 10); and let y = Number("");. What are the values of x and y? Why are they different? In what real-world scenario could this inconsistency cause a bug, and how would you guard against it?Lesson Summary
NaN (Not-a-Number) is JavaScript's way of signaling that a numeric operation failed. It's unique because it is never equal to itself, so you must detect it using isNaN() (which coerces first) or the stricter Number.isNaN() (which checks without coercion). NaN is "contagious"—once it enters a calculation, every subsequent result becomes NaN too.
To convert strings into numbers, use parseInt(string, 10) for whole numbers and parseFloat(string) for decimals. Both scan left-to-right and tolerate trailing non-numeric characters, making them ideal for messy real-world input. For strict full-string conversion, use Number(). Always validate the result with an isNaN check before using it in calculations to prevent silent bugs in your programs.