ToolMight LogoToolMight

"Guess the Output" JS Trivia Sprint

Test your JavaScript type coercion, hoisting, and scope knowledge in a 60s sprint.

Streak: 0
Score: 0

Ready for the JS Trivia Sprint?

You have 60 seconds to predict what JavaScript snippets log or evaluate to. A single wrong answer breaks your streak and ends the sprint!

Mastering JavaScript Weirdness, Type Coercion & Quirks

JavaScript is celebrated for its flexibility, but infamous for counter-intuitive evaluation rules resulting from dynamic typing, implicit type coercion, and historical ECMAScript specifications. Understanding these nuances is essential for writing resilient code and acing technical frontend interviews.

Implicit Type Coercion & The ToPrimitive Operation

Whenever JavaScript encounters mismatched operand types in binary expressions, the engine invokes internal abstract operations specified by ECMAScript. The most critical is ToPrimitive(input [, PreferredType]):

Addition (+) with Strings"53"
'5' + 3 => "53"

String concatenation takes precedence over numeric addition.

Subtraction (-) forces Numbers2
'5' - 3 => 2

Subtraction operator only exists for numeric mathematical math.

Array Addition""
[] + [] => ""

Both arrays call [].toString(), resulting in empty string concatenation.

Array plus Object"[object Object]"
[] + {} => "[object Object]"

Object.prototype.toString() yields "[object Object]".

The Not-Array Paradoxtrue
[] == ![] => true

![] is false; [] coerces to '' then 0; false coerces to 0 (0 == 0).

Boolean Numeric Addition2
true + true => 2

Booleans coerce to 1 for numeric mathematical addition.

Need to inspect or sanitize complex nested JSON payloads?JSON Formatter

The JavaScript Event Loop: Microtasks & Macrotasks

JavaScript is single-threaded, coordinating asynchronous operations using an event loop with two distinct task queues:

Microtask Queue (Immediate Priority)

Handles Promise.then(), catch(), queueMicrotask(), and MutationObserver. Microtasks execute immediately after synchronous execution, before rendering or yielding to macrotasks.

Macrotask Queue (Timer Queue)

Handles setTimeout(), setInterval(), and user UI events. A new macrotask only executes after all pending microtasks have completely drained.

JavaScript / Event Loop Execution Order
console.log("1");
setTimeout(() => console.log("2"), 0); // Macrotask scheduled
Promise.resolve().then(() => console.log("3")); // Microtask queued
console.log("4");

// Final Console Output: "1" -> "4" -> "3" -> "2"

Variable Hoisting & The Temporal Dead Zone (TDZ)

var Declarations

Hoisted to the top of its enclosing function scope and initialized with undefined. Accessing before assignment returns undefined.

let & const (TDZ)

Hoisted to block scope but left uninitialized in the Temporal Dead Zone. Accessing before declaration throws an instant ReferenceError.

Function Declarations

Function declarations (function foo() {}) are hoisted with their bodies intact, allowing invocations before the physical declaration line.

Prototypal Inheritance & 'this' Binding Mechanics

Default & Implicit Binding

A standalone function call binds this to global window (or undefined in strict mode). When invoked as obj.method(), this implicitly binds to obj.

Arrow Functions & Lexical 'this'

Arrow functions do not bind their own this, arguments, or super. They permanently inherit this from their enclosing lexical scope.

IEEE 754 Floating-Point Precision Quirk

JavaScript numbers are 64-bit binary floating-point values. Fractions like 0.1 cannot be stored cleanly in base-2, yielding 0.1 + 0.2 === 0.30000000000000004. Compare float equality using Math.abs(a - b) < Number.EPSILON.

FAQ Guide

Frequently Asked Questions

Why does [] + [] evaluate to an empty string?

Binary + coerces arrays to primitives via the internal ToPrimitive operation. Converting an empty array [] yields an empty string '', resulting in '' + '' = ''.

Why does [] == ![] evaluate to true?

The logical NOT operator (!) runs first, turning [] into boolean false. Loose equality (==) coerces boolean false to 0, and the empty array [] to '' then 0, leading to 0 == 0, which is true.

Why is typeof NaN equal to 'number'?

NaN stands for 'Not-a-Number', but the IEEE 754 floating-point specification defines it as a numeric value representing an undefined calculation (such as Math.sqrt(-1)).

How does the microtask queue differ from the macrotask queue?

Microtasks (Promise callbacks, queueMicrotask) have strict priority over macrotasks (setTimeout, setInterval). The event loop empties all queued microtasks before proceeding to the next macrotask.

What is the Temporal Dead Zone (TDZ)?

The TDZ is the state between entering a block scope and the line where a let or const variable is declared. Accessing the variable in the TDZ triggers an immediate ReferenceError.

How does 'this' binding differ in arrow functions?

Regular functions bind 'this' dynamically at call time based on the invoking context. Arrow functions do not have their own 'this'; they inherit 'this' statically from their outer lexical scope.