🟦 JavaScript Deep Dive – Issue #1
The Strange Parts of JavaScript: Why the Language Behaves Like That
Welcome to the first issue of the JavaScript Deep Dive newsletter — a series for developers who want to go beyond tutorials and explore the deeper mechanics that make JavaScript powerful, weird, and endlessly fascinating.
Today we’re tackling one of the most polarizing aspects of the language:
Its strange, unexpected, and occasionally cursed behaviors.
If you’ve ever looked at a line of JavaScript and said:
“Why… why would it do THAT?”
This issue is for you.
🧠 Why JavaScript Has So Many Weird Parts
JavaScript was originally built in 10 days, intended as a small scripting language inside Netscape Navigator.
Over decades, JavaScript has expanded dramatically — but backward compatibility means every odd behaviour must continue to work forever.
This creates a language that is both:
- Brilliant (first-class functions, closures, prototypes, async model)
- Bizarre (type coercion, scoping oddities, nonsensical comparisons)
Let’s unpack the pieces that have tripped up even experienced devs.
🟨 1. The Wild West of Type Coercion
JavaScript loves to “help” by converting values for you — even when you don’t want it to.
Consider this classic monster:
console.log([] == ![]); // true
Why??
Break it down:
| Step | Explanation |
|---|---|
![] | Array is truthy → ![] becomes false |
[] == false | Now JS tries to coerce both sides |
[] → "" | An empty array becomes an empty string |
"" == false | Empty string becomes number → 0 |
false → 0 | Boolean becomes number → 0 |
0 == 0 | Now it’s true |
Lesson:
Always use === unless you explicitly want coercion.
🟨 2. The Mystery of null and undefined
They look similar, but behave differently.
| Value | Meaning | Type |
|---|---|---|
undefined | variable declared but not assigned | "undefined" |
null | explicitly “nothing” | "object" (legacy bug!) |
Try this:
typeof null; // "object"
This is one of JavaScript’s oldest bugs — frozen in time because millions of websites depend on it.
Best practice:
Use null intentionally
Use undefined sparingly or only when JS assigns it
🟨 3. Hoisting: The Source of 1,000 Confusions
JavaScript “moves” declarations to the top of scope during compilation.
Try this:
console.log(a);
var a = 10;
Output:
undefined
Because JS treats it like:
var a;
console.log(a);
a = 10;
But with let and const:
console.log(a);
let a = 10;
Output:
ReferenceError: Cannot access 'a' before initialization
This is the Temporal Dead Zone (TDZ) — a safer behavior that avoids accidental hoisting bugs.
🟨 4. Closures: Powerful but Dangerous
Closures allow inner functions to remember external variables.
But that memory can lead to unexpected behavior.
Classic example:
var buttons = [];
for (var i = 0; i < 3; i++) {
buttons[i] = function() {
console.log(i);
}
}
buttons[0](); // 3
buttons[1](); // 3
buttons[2](); // 3
Why?
Because var is function-scoped — each function closes over the same i variable.
Fix it with let:
for (let i = 0; i < 3; i++) {
buttons[i] = () => console.log(i);
}
Or use an IIFE:
for (var i = 0; i < 3; i++) {
buttons[i] = (function(n) {
return function() { console.log(n); }
})(i);
}
🟨 5. The Prototype Chain: Often Misunderstood
JavaScript doesn’t have classical inheritance — it has prototype inheritance.
Try this:
const obj = {};
console.log(obj.toString);
Where does toString come from?
Not obj, but its prototype:
obj → Object.prototype → null
Understanding this chain is essential for:
- Performance tuning
- Object creation patterns
- Custom data structures
- Using
classsyntax properly
Pro tip:
Use Object.create(null) if you need a truly empty object (e.g., for safe dictionaries).
🟦 🔍 “Wait… What Just Happened?” Section (Fun Examples)
These are great to include to keep readers engaged.
1. Object + Number
console.log({} + 1); // "[object Object]1"
2. Array Holes
const a = [1, , 3];
console.log(a.length); // 3
console.log(a[1]); // undefined but NOT present
3. Boolean Drama
true + true === 2 // true
true == 1 // true
true === 1 // false
🧩 Mini Exercises for Readers
To increase engagement, add these at the end.
1. What will this output?
console.log([] + []);
2. What about this?
console.log({} == {});
3. Explain this output:
console.log("5" - 2);
console.log("5" + 2);
🟦 Best Practices to Avoid JavaScript Weirdness
✔ Prefer ===
✔ Prefer let and const
✔ Avoid implicit coercion
✔ Avoid relying on hoisting
✔ Don’t modify built-in prototypes
✔ Understand how closures capture memory
✔ Use “strict mode”
✔ Write pure functions whenever possible
🏁 Final Thoughts
JavaScript’s weird behaviors aren’t flaws — they’re artifacts of its evolution and flexibility.
By understanding them, you’ll:
- Write fewer bugs
- Debug faster
- Understand high-level frameworks better
- Think at an engine level
In the next issue, we’ll dive into something every serious JavaScript developer must understand:
👉 The Event Loop — Microtasks, Macrotasks & Hidden Async Behaviors