September 23, 2026
BrainFuc*s of JavaScript - A series(Part 1)

Embracing the Chaos: JavaScript's Most Humbling Quirks
JavaScript has a unique ability to make even the most seasoned engineers question their sanity. Beneath its flexible syntax lies an engine driven by implicit coercion, legacy design choices, and a ruthless event loop. Here is a breakdown of the language's most counterintuitive behaviors and the mechanics that cause them.
The parseInt Scientific Notation Trap
Most developers know that parseInt() parses a string and returns an integer. But passing a small float yields a bizarre result.
javascriptconsole.log(parseInt(0.0000005)); // 5
The Engine's Logic: parseInt expects a string as its first argument. When you pass a number, JavaScript implicitly coerces it to a string first. Very small (or very large) numbers in JavaScript are stringified using scientific notation. Thus, String(0.0000005) becomes "5e-7". parseInt reads character by character until it hits a non-numeric character. It reads the "5", stops at the "e", and returns 5.
The Object Key Stringification Overwrite
When using objects as keys within another object, the result is rarely what you expect.
javascriptconst map = {}; const objA = { id: 1 }; const objB = { id: 2 }; map[objA] = "First"; map[objB] = "Second"; console.log(map[objA]); // "Second"
The Engine's Logic: Standard JavaScript objects can only have strings or Symbols as keys. When you try to use an object as a key, JavaScript calls the object's toString() method. For plain objects, toString() returns "[object Object]".
Therefore, map[objA] and map[objB] are both assigning a value to map["[object Object]"]. The second assignment simply overwrites the first. This fundamental quirk is exactly why Map and WeakMap were introduced in ES6, as they allow true object references to act as keys without type coercion.
The typeof Temporal Dead Zone Trap
A common defensive programming technique is using typeof to check if a variable exists without throwing an error.
javascriptconsole.log(typeof undeclaredVar); // "undefined" (Safe!) console.log(typeof declaredLater); // ReferenceError! let declaredLater = "Hello";
The Engine's Logic: Historically, typeof was 100% safe to use on undeclared variables. However, the introduction of block-scoped variables (let and const) created the Temporal Dead Zone (TDZ). The engine knows declaredLater exists in the block scope because of hoisting, but it remains uninitialized. Attempting to access a variable in its TDZ—even with a "safe" operator like typeof—throws a ReferenceError to prevent you from using uninitialized data.
The Infinity Paradox of Math.max and Math.min
It sounds like a riddle, but in JavaScript, the maximum is less than the minimum.
javascriptconsole.log(Math.max() < Math.min()); // true
The Engine's Logic: When called with no arguments, Math.max() returns -Infinity and Math.min() returns Infinity. The logic under the hood makes sense for comparison algorithms: the initial comparator for a "maximum" search must be set to the lowest possible value so that any actual argument provided will be larger than the initial state. Conversely, the initial comparator for a "minimum" search must start at the highest possible value (Infinity).
The Microtask Queue Starvation
Understanding the event loop is a rite of passage, but the strict distinction between macrotasks (setTimeout) and microtasks (Promises) can lead to literal application lockups if abused.
javascriptsetTimeout(() => console.log("Timeout"), 0); Promise.resolve().then(function loop() { Promise.resolve().then(loop); });
The Engine's Logic: You might expect the engine to alternate between tasks, eventually printing "Timeout". It never will. The event loop prioritizes the microtask queue (Promises, queueMicrotask). It will entirely empty the microtask queue before it ever moves to the macrotask queue. Because the Promise continually queues another microtask, the microtask queue never empties, starving the macrotask queue entirely and indefinitely hanging the thread.
These quirks aren't just trivia; they are a direct reflection of JavaScript's evolution from a 10-day prototype to the backbone of the modern web. Understanding the mechanics beneath them—how the engine coerces types, manages memory, and loops through tasks—turns these frustrating edge cases into predictable architectural constraints.