SECTION 1
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.
1985 • IEEE 754 Standard Published
1995 • JavaScript Is Born
parseInt() and parseFloat() for parsing user input.1999 • ECMAScript 3 Formalizes isNaN()
isNaN() function, giving developers a standard way to check whether a value is NaN.2015 • ES6 Introduces Number.isNaN()
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.
SECTION 2
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".KEY TAKEAWAY
isNaN() or Number.isNaN()) to detect it and decide what to do next.SECTION 3
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.
SECTION 4
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
GLOBAL isNaN()
The global 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.
STRICT Number.isNaN()
The stricter 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
parseInt SYNTAX
string — the text to parse (leading whitespace is trimmed).
radix — the base of the number system (2 for binary, 10 for decimal, 16 for hex). Always specify 10 for normal decimal parsing.
parseFloat SYNTAX
string — the text to parse. Unlike parseInt, parseFloat does not accept a radix parameter because it always works in base 10. It recognizes one decimal point and exponent notation (e.g., "1.5e3" → 1500).
SECTION 5
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 |
Comparison of three number-conversion approaches in JavaScript
"px" or "kg", use parseFloat or parseInt. If the string should be purely numeric, Number() is the strictest option.SECTION 6
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.
Parsing a Price from User Input
- 1
Step 1 — Receive the Input
The user types"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";userInput is the string"19.99" - 2
Step 2 — Parse with parseFloat()
Since we expect a price with decimal places, we useparseFloat()rather thanparseInt()(which would chop off the cents).let price = parseFloat(userInput);The parser reads1,9,.,9,9and converts them into the number 19.99.price =19.99 - 3
Step 3 — Validate with isNaN()
Before using the price in a calculation, we check whether parsing succeeded. If the user had typed something like"free",parseFloat()would have returned NaN.if (isNaN(price)) { console.log("Please enter a valid number."); } else { console.log("Price accepted: $" + price); }Since price is 19.99 (not NaN), the output is:"Price accepted: $19.99" - 4
Step 4 — Calculate the Total
Now we can safely use the number in arithmetic. Let's say the user wants 3 items:let quantity = parseInt("3", 10); let total = price * quantity;Notice we usedparseInt()with radix10for the quantity because it's always a whole number.total =59.97 - 5
Step 5 — Handle Edge Cases
What if the user typed"19.99 dollars"? BecauseparseFloat()ignores trailing text, it would still return19.99. ButNumber("19.99 dollars")would returnNaNbecauseNumber()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)
SECTION 7
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 |
Strengths and pitfalls of each conversion method
Common Pitfall
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.KEY TAKEAWAY
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.SECTION 8
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 |
How today's concepts connect to future JavaScript topics
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.
SECTION 9
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.
Question 1: CONCEPTUAL
NaN === NaN return false in JavaScript? What function should you use instead to check if a value is NaN?Show answer
Number.isNaN(value) for a strict check, or the global isNaN(value) if you also want to detect values that would become NaN after type coercion.Question 2: BASIC CALCULATION
parseInt("100px", 10)
b) parseFloat("7.5em")
c) parseInt("abc", 10)Show answer
100 — parseInt reads the digits 1, 0, 0, then stops at the letter "p." b) 7.5 — parseFloat reads 7, the decimal point, and 5, then stops at "e" (which here is not part of exponent notation since it's followed by "m"). c) NaN — the very first character "a" is not a digit, so parseInt cannot extract any number at all and returns NaN.Question 3: INTERMEDIATE
isNaN("hello") and Number.isNaN("hello"). What does each return, and why?Show answer
isNaN("hello") returns true because the global isNaN function first coerces the argument by calling Number("hello"), which produces NaN, and then checks that result. On the other hand, Number.isNaN("hello") returns false because Number.isNaN does not coerce its argument. The string "hello" is a string, not the numeric value NaN, so the strict check reports false. Use Number.isNaN when you specifically want to know if a value is already the NaN number.Question 4: APPLIED
"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.Show answer
let input = "72°F";
let fahrenheit = parseFloat(input);
if (isNaN(fahrenheit)) {
console.log("Error: invalid temperature.");
} else {
let celsius = (fahrenheit - 32) * 5 / 9;
console.log(celsius.toFixed(1) + "°C");
}
We use parseFloat because temperatures can have decimals. It reads "72" and stops at the degree symbol. The isNaN check ensures we don't attempt math on a bad value. The result is approximately 22.2°C.Question 5: CRITICAL THINKING
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?Show answer
x is NaN because parseInt finds no digits to parse in an empty string. y is 0 because Number("") treats an empty string as zero—a design decision baked into the ECMAScript specification. This inconsistency could cause a bug in a shopping cart: if a user clears a quantity field (making it empty) and you use Number("") to read it, the system silently calculates a $0 total instead of showing an error. To guard against this, you can check for an empty string before conversion: if (input.trim() === "") { /* show error */ }. Alternatively, use parseInt or parseFloat, which correctly return NaN for empty strings.SUMMARY
Lesson Summary
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.