Bonus Material Understanding JavaScript’s Weird But Powerful Behavior

This bonus pack is designed to train your JavaScript intuition.
The goal is not to run the code — the goal is to predict the behavior before execution.

First 3 chapters of the book here https://basescripts.com/the-weird-the-subtle-and-the-powerful-in-javascript-book-free-first-3-chapters

The Weird, the Subtle, and the Powerful in JavaScript

US : https://www.amazon.com/dp/B0GBTM5SCY 

Canada : https://www.amazon.ca/dp/B0GBTM5SCY 

Why JavaScript feels weird (and why that’s actually useful)

JavaScript wasn’t designed in a perfect lab environment. It was built fast, had to run in browsers, and—most importantly—it can’t break the web. That means some “odd” behaviors are permanent, and modern features have to stack on top of older rules.

If you learn the rules behind the weirdness, you stop guessing—and start predicting.

Here are a few of the famous “wait…what?” moments (and what they teach):

1) Coercion: JavaScript loves converting types

[] == false   // true

0  == ”      // true

true + true   // 2

What’s happening?
== triggers type conversion. Arrays can become strings ([] -> “”), booleans become numbers (true -> 1), and comparisons start behaving like puzzles.

Practical rule: prefer === unless you really know the coercion path you want.

2) Hoisting: declarations are processed before execution

console.log(a);

var a = 10;

Output: undefined

Why?
var a is hoisted and initialized to undefined during the creation phase, then assigned later.

Now compare:

console.log(b);

let b = 10;

This throws a ReferenceError due to the Temporal Dead Zone (TDZ)—b exists but isn’t initialized yet.

Practical rule: use let/const, and declare before use.

3) Closures: the “superpower” behind modern JS patterns

function counter(){

  let count = 0;

  return () => ++count;

}

const c = counter();

c(); // 1

c(); // 2

Closures are why functions can remember state, even after the outer function finishes. They power:

  • event handlers
  • memoization
  • debouncing
  • private variables
  • module patterns

Practical rule: closures store live references, so be mindful of shared state and memory.


🧠 How to Use This Bonus Pack

For each item:

  1. Pause
  2. Predict the result
  3. Explain why it happens
  4. Run the code
  5. Compare your mental model with reality

If your prediction was wrong — you just learned something valuable.


🔹 CHAPTER 1 — JavaScript’s Weird Parts

🔮 Proactive Thinking Prompts

Use these in ChatGPT / Gemini:

  1. “Explain why JavaScript keeps historical bugs instead of fixing them.”
  2. “Walk me step-by-step through how JavaScript evaluates [] == ![] internally.”
  3. “Explain JavaScript’s type coercion rules like I’m debugging production code at 2AM.”
  4. “Show how == comparisons differ from === with real bug scenarios.”
  5. “Explain why JavaScript tries to ‘help’ developers and how that backfires.”

❓ Mini Quiz — Predict the Output

Q1

console.log([] + []);

A) []
B) “”
C) “[]”
D) Error

Answer: B
Arrays convert to strings → “” + “”


Q2

console.log(1 + ‘2’ – 1);

A) 11
B) 12
C) 2
D) NaN

Answer: C
1 + ‘2’ → “12” → “12” – 1 → 11 ← wait… trick question
Correct flow: “12” – 1 → 11
✔ Correct answer: B (11)


Q3

console.log(false == ‘0’);

A) true
B) false

Answer: A
‘0’ → 0, false → 0


🛠 Exercise — Rewrite Safely

Rewrite without coercion bugs:

if (value == false) { … }

Solution

if (value === false) { … }

—or explicitly convert:

if (Boolean(value) === false) { … }


🔹 CHAPTER 2 — Hoisting & TDZ

🔮 Proactive Thinking Prompts

  1. “Simulate the JavaScript creation phase for this script.”
  2. “Explain why let variables exist but cannot be accessed before initialization.”
  3. “Show how hoisting prevents or causes bugs in real applications.”
  4. “Compare hoisting behavior between var, let, and function.”
  5. “Explain TDZ using a timeline diagram.”

❓ Mini Quiz — Predict the Output

Q1

console.log(a);

let a = 5;

A) undefined
B) null
C) ReferenceError
D) 5

Answer: C
TDZ prevents access before initialization.


Q2

test();

function test() {

  console.log(‘Hi’);

}

A) Error
B) Hi

Answer: B
Function declarations are fully hoisted.


Q3

run();

var run = () => console.log(‘Run’);

A) Run
B) undefined
C) TypeError

Answer: C
run is hoisted as undefined, not as a function.


🛠 Exercise — Fix the Hoisting Bug

calculate();

const calculate = () => console.log(‘Done’);

Solution

const calculate = () => console.log(‘Done’);

calculate();


🔹 CHAPTER 3 — Scope & Closures

🔮 Proactive Thinking Prompts

  1. “Explain closures using a memory snapshot diagram.”
  2. “Why do closures store references instead of copies?”
  3. “Show how closures can accidentally leak memory.”
  4. “Explain lexical scope vs dynamic scope.”
  5. “Rewrite this closure to reduce memory usage.”

❓ Mini Quiz — Predict the Output

Q1

let x = 1;

function outer() {

  let x = 2;

  return () => x;

}

console.log(outer()());

A) 1
B) 2

Answer: B
Closures use lexical scope, not call location.


Q2

const funcs = [];

for (let i = 0; i < 3; i++) {

  funcs.push(() => i);

}

console.log(funcs[0](), funcs[1](), funcs[2]());

A) 0 1 2
B) 3 3 3

Answer: A
let creates a new binding per iteration.


Q3

function test() {

  console.log(a);

  let a = 10;

}

test();

A) undefined
B) 10
C) ReferenceError

Answer: C
TDZ inside function scope.


🛠 Exercise — Build a Real Closure

Task: Create a once() utility

const once = fn => { /* your code */ };

Solution

function once(fn) {

  let called = false;

  let result;

  return (…args) => {

    if (!called) {

      result = fn(…args);

      called = true;

    }

    return result;

  };

}


🚀 Advanced Challenge (Newsletter Bonus)

Before running this code — write down the output and WHY:

let a = 1;

(function() {

  console.log(a);

  var a = 2;

})();

Answer

undefined

Why?

  • var a is hoisted inside the IIFE
  • Inner a shadows outer a
  • Assignment happens after console.log

🧩 Final Mental Model Check

Ask yourself:

  • Can I predict execution before running code?
  • Do I understand why hoisting exists?
  • Can I explain closures without saying “magic”?
  • Can I debug by reasoning instead of trial-and-error?

If yes — you’re no longer using JavaScript.
You’re thinking in JavaScript.