-
Section 1: Getting Started
-
Section 2: Core Syntax and Types
-
Section 3: Strings and Numbers in Depth
-
Section 4: Control Flow
-
Section 5: Functions
-
Section 6: Objects and Arrays
-
Section 7: Maps, Sets, and Symbols
-
Section 8: Asynchronous JavaScript
-
Section 9: Object-Oriented and Prototypes
-
Section 10: The DOM
-
Section 11: Browser APIs
-
Section 12: Modern JavaScript (ES2015-ES2025)
-
Section 13: Functional Programming Patterns
-
Section 14: Error Handling and Debugging
-
Section 15: Testing
-
Section 16: Accessibility for JavaScript Developers
-
Section 17: Internationalization and Localization
-
Section 18: Performance
-
Section 19: Node.js Fundamentals
-
Section 20: Regular Expressions
-
Section 21: Design Patterns in JavaScript
-
Section 22: Security Basics
-
Section 23: Data Structures and Algorithms in JavaScript
-
Section 24: Practical Projects
-
Section 25: More Advanced Async Patterns
-
Section 26: More Object and Class Practice
-
Section 27: Working with Dates and Internationalization
-
Section 28: Web Components
-
Section 29: More DOM and Browser Practice
-
Section 30: Build Tooling for Vanilla JavaScript
-
Section 31: More Practice Projects
-
Section 32: Interview and Algorithm Practice
-
Section 33: Error Objects (MDN Reference)
-
Section 34: TypedArrays and Binary Data
-
Section 35: Reflection and Metaprogramming (MDN Reference)
-
Section 36: More Global Functions (MDN Reference)
16: Practice Exercise: Type Coercion Puzzles
I've spent more hours than I care to admit debugging a "ghost in the machine" that turned out to be a single plus sign. JavaScript's type coercion is one of those features that feels like a convenience when you're first learning—who doesn't love it when the language "just figures out" what you mean?—but in a professional codebase, it's a liability. When you let the engine guess your intent, you're essentially gambling that the engine's guess matches your logic.
The trap of the "helpful" plus sign
Imagine you're building a simple feature to calculate a shipping total. You're grabbing a value from an input field, which, as you know, always comes back as a string. A naive approach looks like this:
let subtotal = "29.99";
let shipping = 5.00;
let total = subtotal + shipping;
// Result: "29.995"
It’s a classic mistake. Because the + operator is overloaded in JavaScript to handle both addition and string concatenation, the engine sees a string and says, "Oh, we must be building a sentence here," and just glues the numbers together. I've seen this happen in production environments where a price total suddenly becomes a massive string of digits, and the customer is very confused why their order costs twenty-nine dollars and ninety-nine cents... five.
Choosing explicit conversion over implicit guesses
The better way—the way I expect to see in any pull request I review—is to be loud and explicit about your intentions. Don't make the engine guess; tell it exactly what the data is. By using Number() or parseFloat(), you move the point of failure to the start of the operation rather than the end.
let subtotal = "29.99";
let shipping = 5.00;
let total = Number(subtotal) + shipping;
// Result: 34.99
Now, the logic is bulletproof. If subtotal happens to be something completely wild—like the string "Free"—Number("Free") returns NaN. While NaN isn't a "pretty" result, it's infinitely better than "Free5" because it tells you immediately that your data is corrupt. I'd much rather have a program that crashes or logs an error than one that silently calculates the wrong price and charges a credit card for the wrong amount.
The danger of the loose equality check
This same philosophy applies to how we compare values. You'll see == (loose equality) in a lot of old tutorials, and it seems handy because it coerces types for you. For example, 0 == false is true, and "" == 0 is also true. In a small script, that's a shortcut. In a large application, that's a bug waiting to happen.
When you use === (strict equality), you're telling JavaScript: "These must be the same type AND the same value." If you're checking if a user's input is 0, you don't want a blank string to pass that test. By sticking to strict equality, you force yourself to handle your types correctly before the comparison happens. It adds one extra line of code for the conversion, but it saves you three hours of debugging on a Friday afternoon.
📋 Practical Task
Fixing the "Leaky Checkout Cart" Logic
You've inherited a piece of code for a shopping cart that is producing bizarre results. The current implementation relies entirely on implicit coercion, and it's causing the totals to be calculated as strings and the "Empty Cart" check to fail intermittently.
Your Task: Rewrite the calculateFinalPrice function. You must remove all loose equality checks (==) and ensure that all string inputs are explicitly converted to numbers before any arithmetic takes place. The function should return a proper number, not a string.
function calculateFinalPrice(cartTotal, taxRate, discountCode) {
// BUGGY CODE:
// 1. cartTotal is passed as a string (e.g., "100")
// 2. taxRate is a number (e.g., 0.07)
// 3. discountCode is either "10" (as a string) or null
let total = cartTotal + (cartTotal * taxRate);
if (discountCode == "10") {
total = total - 10;
}
if (cartTotal == 0) {
return 0;
}
return total;
}
// Test Case:
console.log(calculateFinalPrice("100", 0.07, "10"));
// Current wrong output: "1007.0" (due to "100" + 7)
// Expected correct output: 97
There are no comments for now.