JavaScript Utility Methods
We've covered type conversions — now let's learn a batch of utility methods you'll use every day. Think of them as a Swiss army knife — each one is simple, but you'll miss any one of them when you need it.
📖 Summary
parseInt and parseFloat
Parse numbers from the beginning of a string, stopping at the first non-numeric character:
<script>
console.log(parseInt("42px")); // 42
console.log(parseInt("3.14")); // 3 (integer part only)
console.log(parseFloat("3.14")); // 3.14
console.log(parseFloat("3.14abc")); // 3.14
console.log(parseInt("abc42")); // NaN (doesn't start with a number)
</script>
The second argument of parseInt specifies the radix:
<script>
console.log(parseInt("FF", 16)); // 255 (hexadecimal)
console.log(parseInt("10", 2)); // 2 (binary)
</script>
Pitfall: Without a radix, strings starting with 0x are parsed as hexadecimal. Always pass 10 as the second argument.
isNaN vs Number.isNaN
| Method | Behavior |
|---|---|
isNaN(value) |
Converts to number first, then checks if it's NaN |
Number.isNaN(value) |
Strictly checks if the value is NaN (no conversion) |
<script>
console.log(isNaN("hello")); // true (Number("hello") → NaN, then true)
console.log(Number.isNaN("hello")); // false ("hello" itself is not NaN)
console.log(isNaN(undefined)); // true
console.log(Number.isNaN(undefined));// false
</script>
Conclusion: Use Number.isNaN() — it won't silently coerce types.
toFixed
Controls decimal places, returns a string:
<script>
console.log((3.14159).toFixed(2)); // "3.14"
console.log((3.1).toFixed(4)); // "3.1000" (padded with zeros)
console.log((3.145).toFixed(2)); // "3.14" or "3.15" (floating-point precision issue, rounding not guaranteed)
</script>
Note that toFixed returns a string — use Number() to convert it back for calculations.
toString
Converts a number to a string, with optional radix support:
<script>
console.log((255).toString()); // "255"
console.log((255).toString(16)); // "ff"
console.log((8).toString(2)); // "1000"
console.log((100).toString(8)); // "144"
</script>
Booleans and arrays also have toString:
<script>
console.log(true.toString()); // "true"
console.log([1,2,3].toString()); // "1,2,3"
</script>
Number.isInteger
Checks whether a value is an integer:
<script>
console.log(Number.isInteger(5)); // true
console.log(Number.isInteger(5.0)); // true (5.0 is just 5)
console.log(Number.isInteger(5.5)); // false
console.log(Number.isInteger("5")); // false (a string is not an integer)
console.log(Number.isInteger(NaN)); // false
</script>
Math.trunc and Math.sign
Math.trunc simply chops off the decimal part (no rounding):
<script>
console.log(Math.trunc(4.9)); // 4
console.log(Math.trunc(-4.9)); // -4
console.log(Math.trunc(4.1)); // 4
</script>
Math.sign returns the sign of a number:
<script>
console.log(Math.sign(5)); // 1
console.log(Math.sign(-5)); // -1
console.log(Math.sign(0)); // 0
console.log(Math.sign(-0)); // -0
console.log(Math.sign(NaN)); // NaN
</script>
Limitations of typeof
typeof usually works for type checking, but there are a few classic gotchas:
<script>
console.log(typeof 42); // "number" ✅
console.log(typeof "hello"); // "string" ✅
console.log(typeof true); // "boolean" ✅
console.log(typeof undefined); // "undefined" ✅
console.log(typeof null); // "object" ❌ This is a historical bug!
console.log(typeof []); // "object" ❌ Arrays are also objects
console.log(typeof {}); // "object" ✅
console.log(typeof function(){}); // "function" ✅
</script>
typeof null === "object" is a "veteran bug" in JavaScript — it's been around since 1995 and can never be fixed. Use value === null to check for null. Use Array.isArray() to check for arrays.
Example: Price Calculator
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Price Calculator</title>
<style>
body { font-family: sans-serif; padding: 20px; }
.calc { max-width: 440px; margin: 16px auto; padding: 24px; background: #f9f9f9; border-radius: 12px; }
.row { margin: 12px 0; display: flex; align-items: center; gap: 10px; }
label { width: 80px; font-weight: bold; }
input { padding: 8px 12px; font-size: 16px; border: 2px solid #ccc; border-radius: 6px; flex: 1; }
button { padding: 10px 24px; font-size: 16px; border: none; border-radius: 6px; cursor: pointer; background: #4a90d9; color: #fff; width: 100%; margin-top: 8px; }
button:hover { background: #357abd; }
.result { margin-top: 16px; padding: 16px; background: #fff; border-radius: 8px; border: 2px solid #5cb85c; }
.result div { margin: 4px 0; }
.total { font-size: 22px; font-weight: bold; color: #d9534f; }
</style>
</head>
<body>
<h2 style="text-align:center;">Price Calculator</h2>
<div class="calc">
<div class="row">
<label>Unit Price:</label>
<input type="text" id="price" value="29.90" placeholder="e.g. 29.90" />
</div>
<div class="row">
<label>Quantity:</label>
<input type="text" id="qty" value="3" placeholder="e.g. 3" />
</div>
<div class="row">
<label>Discount:</label>
<input type="text" id="discount" value="0.85" placeholder="e.g. 0.85 (15% off)" />
</div>
<button id="calc">Calculate</button>
<div class="result" id="result" style="display:none;"></div>
</div>
<script>
document.getElementById("calc").addEventListener("click", function() {
const priceStr = document.getElementById("price").value.trim();
const qtyStr = document.getElementById("qty").value.trim();
const discountStr = document.getElementById("discount").value.trim();
const price = parseFloat(priceStr);
const qty = parseInt(qtyStr, 10);
const discount = parseFloat(discountStr);
if (Number.isNaN(price) || price <= 0) {
alert("Invalid unit price! Please enter a positive number.");
return;
}
if (Number.isNaN(qty) || qty <= 0 || !Number.isInteger(qty)) {
alert("Invalid quantity! Please enter a positive integer.");
return;
}
if (Number.isNaN(discount) || discount <= 0 || discount > 1) {
alert("Invalid discount! Please enter a decimal between 0 and 1.");
return;
}
const subtotal = price * qty;
const total = subtotal * discount;
const saved = subtotal - total;
document.getElementById("result").style.display = "block";
document.getElementById("result").innerHTML = `
<div>Unit Price: $${price.toFixed(2)}</div>
<div>Quantity: ${qty}</div>
<div>Subtotal: $${subtotal.toFixed(2)}</div>
<div>Discount: ${(discount * 100).toFixed(0)}% off (-$${saved.toFixed(2)})</div>
<div class="total">Total: $${total.toFixed(2)}</div>
`;
});
</script>
</body>
</html>
Example: Input Validation Tool
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Input Validation</title>
<style>
body { font-family: sans-serif; padding: 20px; }
.demo { max-width: 500px; margin: 16px auto; }
.row { margin: 12px 0; display: flex; align-items: center; gap: 10px; }
label { width: 80px; font-weight: bold; }
input { padding: 8px 12px; font-size: 16px; border: 2px solid #ccc; border-radius: 6px; flex: 1; }
input.valid { border-color: #5cb85c; background: #f0fff0; }
input.invalid { border-color: #d9534f; background: #fff0f0; }
.msg { font-size: 13px; margin-left: 90px; }
.msg.valid { color: #5cb85c; }
.msg.invalid { color: #d9534f; }
.methods { margin-top: 20px; padding: 16px; background: #f5f5f5; border-radius: 8px; }
.methods div { margin: 4px 0; font-family: monospace; font-size: 14px; }
</style>
</head>
<body>
<h2 style="text-align:center;">Input Validation Demo</h2>
<div class="demo">
<div class="row">
<label>Age:</label>
<input type="text" id="age" placeholder="Enter age" />
</div>
<div class="msg" id="ageMsg"></div>
<div class="row">
<label>Phone:</label>
<input type="text" id="phone" placeholder="Enter phone number" />
</div>
<div class="msg" id="phoneMsg"></div>
<div class="row">
<label>Amount:</label>
<input type="text" id="amount" placeholder="Enter amount" />
</div>
<div class="msg" id="amountMsg"></div>
<div class="methods" id="methods"></div>
</div>
<script>
function validateAge(value) {
const num = parseInt(value, 10);
if (value.trim() === "") return { valid: false, msg: "Cannot be empty" };
if (Number.isNaN(num)) return { valid: false, msg: "Not a valid integer" };
if (!Number.isInteger(Number(value))) return { valid: false, msg: "Age must be an integer" };
if (num < 0 || num > 150) return { valid: false, msg: "Age range: 0–150" };
return { valid: true, msg: `Valid — you are ${num} years old` };
}
function validatePhone(value) {
const trimmed = value.trim();
if (trimmed === "") return { valid: false, msg: "Cannot be empty" };
if (!/^\d+$/.test(trimmed)) return { valid: false, msg: "Numbers only" };
if (trimmed.length !== 11) return { valid: false, msg: "Phone number must be 11 digits" };
return { valid: true, msg: "Format is correct" };
}
function validateAmount(value) {
const num = parseFloat(value);
if (value.trim() === "") return { valid: false, msg: "Cannot be empty" };
if (Number.isNaN(num)) return { valid: false, msg: "Not a valid number" };
if (num <= 0) return { valid: false, msg: "Amount must be greater than 0" };
return { valid: true, msg: `Valid — amount $${num.toFixed(2)}` };
}
function setupValidation(inputId, msgId, validator) {
const input = document.getElementById(inputId);
const msg = document.getElementById(msgId);
input.addEventListener("input", function() {
const result = validator(input.value);
input.className = result.valid ? "valid" : "invalid";
msg.className = "msg " + (result.valid ? "valid" : "invalid");
msg.textContent = result.msg;
updateMethods();
});
}
setupValidation("age", "ageMsg", validateAge);
setupValidation("phone", "phoneMsg", validatePhone);
setupValidation("amount", "amountMsg", validateAmount);
function updateMethods() {
const age = document.getElementById("age").value;
const phone = document.getElementById("phone").value;
const amount = document.getElementById("amount").value;
document.getElementById("methods").innerHTML = `
<strong>Utility Method Results:</strong>
<div>parseInt("${age}", 10) → ${parseInt(age, 10)}</div>
<div>Number.isNaN(parseInt("${age}")) → ${Number.isNaN(parseInt(age, 10))}</div>
<div>parseFloat("${amount}") → ${parseFloat(amount)}</div>
<div>typeof "${phone}" → "${typeof phone}"</div>
`;
}
</script>
</body>
</html>
Example: typeof and Type Checking
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>typeof Type Checking</title>
<style>
body { font-family: sans-serif; padding: 20px; }
table { border-collapse: collapse; margin: 16px 0; width: 100%; max-width: 700px; }
td, th { border: 1px solid #ddd; padding: 10px 14px; text-align: left; }
th { background: #4a90d9; color: #fff; }
.bug { background: #fff0f0; }
.ok { background: #f0fff0; }
.tip { background: #fff8e1; padding: 12px; border-radius: 6px; border-left: 4px solid #f0ad4e; margin: 16px 0; max-width: 700px; }
</style>
</head>
<body>
<h2>typeof Check for Each Type</h2>
<div id="output"></div>
<script>
const values = [
[42, "Number"],
["hello", "String"],
[true, "Boolean"],
[undefined, "undefined"],
[null, "null ⚠️"],
[[1,2,3], "Array ⚠️"],
[{a:1}, "Object"],
[function(){}, "Function"],
[NaN, "NaN"],
[Infinity, "Infinity"],
];
const rows = values.map(([val, label]) => {
const typeResult = typeof val;
const isBug = (val === null && typeResult === "object") ||
(Array.isArray(val) && typeResult === "object");
const correctWay = val === null ? "value === null" :
Array.isArray(val) ? "Array.isArray(value)" :
"typeof is fine";
return `<tr class="${isBug ? 'bug' : 'ok'}">
<td>${label}</td>
<td><code>${JSON.stringify(val)}</code></td>
<td><code>"${typeResult}"</code></td>
<td>${isBug ? "❌ Inaccurate" : "✅ Correct"}</td>
<td>${isBug ? correctWay : "—"}</td>
</tr>`;
});
document.getElementById("output").innerHTML = `
<table>
<tr><th>Expected Type</th><th>Value</th><th>typeof Result</th><th>Accurate?</th><th>Correct Approach</th></tr>
${rows.join("")}
</table>
<div class="tip">
💡 Remember two edge cases: <code>typeof null</code> returns <code>"object"</code> (historical bug),
and <code>typeof []</code> also returns <code>"object"</code> (arrays are not a distinct type).
Use <code>=== null</code> for null checks, and <code>Array.isArray()</code> for array checks.
</div>
`;
</script>
</body>
</html>
❓ FAQ
parseInt("08") return 0?0 were parsed as octal. "08" is invalid in octal, so it returned 0. Solution: always pass the second argument 10 — i.e. parseInt("08", 10) → 8.toFixed guarantee rounding?(0.1 + 0.2).toFixed(1) might give "0.3" or might not. For precise rounding, use Math.round(num * 100) / 100 before calling toFixed.parseFloat and Number()?parseFloat("42px") returns 42 (parses from the start, stops at the first non-numeric character), while Number("42px") returns NaN (parses the whole string — any non-numeric character causes failure). Use parseFloat to extract numbers from mixed text; use Number() for strict validation.📝 Exercises
- Write a function
parseChineseNumber(str)that parses strings like"3.5元"→3.5,"100人"→100,"约200"→200(usingparseFloat). Handle the case where plain text returnsNaN. - Write a function
formatMoney(amount)that takes a number and returns a string with comma-separated thousands and two decimal places, e.g.1234567.89→"1,234,567.89"(hint: usetoFixedandtoStringwith array methods). - Write a function
getType(value)弥补typeof的缺陷:对null返回null,对数组返回array,其余情况返回typeof的结果。



