· 7 min read

Debunking Myths: Tricky JavaScript Questions You Shouldn’t Fear

Tricky JavaScript interview questions often trigger anxiety - but they’re usually testing reasoning, not rote memorization. This article debunks common myths, explains why interviewers ask these questions, walks through concrete examples, and gives practical strategies to answer them confidently.

Introduction

Interviewers love to ask “tricky” JavaScript questions. They get a reputation for weeding out candidates, but more often they measure how you think under ambiguity, reason about edge cases, and use fundamentals to solve problems. In this post we’ll debunk common myths about these questions, explain why they appear in interviews, walk through canonical examples (with full explanations), and give practical strategies to handle them calmly.

Why interviewers ask tricky JavaScript questions

  • To evaluate problem-solving and reasoning over memorization. A good candidate explains their thinking when faced with surprising behavior.
  • To probe fundamentals: understanding scoping, execution order, memory, and types often distinguishes strong engineers.
  • To reveal debugging approach: can the candidate test hypotheses, run simple experiments, and reason from first principles?

Key myths and the reality behind them

  1. Myth: “Tricky questions are about memorizing weird facts.”

Reality: Many tricky behaviors have logical roots - they follow language design or engine constraints. For example, “typeof null === ‘object’” looks like a bug but is a historical artifact with a clear explanation: older implementations used a tag that made null report as an object; the behavior was kept for compatibility. See MDN on typeof for details: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/typeof

  1. Myth: “If you don’t instantly know the output, you’re doomed.”

Reality: Interviewers expect reasoning. Ask clarifying questions, test small snippets mentally (or on a REPL if allowed), and articulate assumptions. Walk through the code step-by-step - that’s what they value.

  1. Myth: “JavaScript is single-threaded so async questions are trivial.”

Reality: JavaScript uses a single-threaded call stack but an event loop with microtasks and macrotasks; this causes subtle ordering differences (e.g., between Promise callbacks and setTimeout). See MDN on the event loop: https://developer.mozilla.org/en-US/docs/Web/JavaScript/EventLoop

  1. Myth: “Closures are memory leaks.”

Reality: Closures capture references; they don’t inherently leak memory. Memory is held as long as references are reachable. Understand lifetimes rather than blaming closures. See MDN on closures: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures

  1. Myth: “If a JS question is tricky, the answer is an obscure corner case.”

Reality: Often the trick comes from combining two well-known behaviors (e.g., hoisting + temporal dead zone). If you can reason about each part, you can predict the whole.

Concrete examples (common interview/quiz items)

Example A - var loop + setTimeout

What does this log?

for (var i = 0; i < 3; i++) {
  setTimeout(() => console.log(i), 10);
}

Answer and reasoning

  • Output: 3, 3, 3
  • Why: var is function-scoped. The callbacks run after the loop finishes, and the single i variable has value 3. The callbacks all reference the same i.

Better versions

  • Use let (block-scoped):
for (let i = 0; i < 3; i++) {
  setTimeout(() => console.log(i), 10);
}
// logs 0, 1, 2
  • Or capture i in a closure at each iteration:
for (var i = 0; i < 3; i++) {
  (j => setTimeout(() => console.log(j), 10))(i);
}

This example demonstrates reasoning about scope and execution timing.

References: MDN var/let/const and scoping patterns: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let

Example B - == vs === and coercion surprises

Predict the result:

0 == '0'; // ?
0 === '0'; // ?
'' == false; // ?
NaN === NaN; // ?
Object.is(NaN, NaN); // ?

Answers and short explanations

  • 0 == '0' is true: loose equality coerces types (string -> number).
  • 0 === '0' is false: strict equality compares type and value.
  • '' == false is true: loose equality coercion makes both falsy values coerce to 0.
  • NaN === NaN is false: NaN is not equal to itself by IEEE rules.
  • Object.is(NaN, NaN) is true: Object.is treats NaN as equal to NaN.

Reference: MDN on equality comparisons: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Equality_comparisons_and_sameness

Example C - Hoisting and the Temporal Dead Zone

What happens here?

console.log(a);
var a = 2;

console.log(b);
let b = 3;

Answer and reasoning

  • First console.log prints undefined. var declarations are hoisted: the variable is created and initialized to undefined at the start of its scope.
  • The second throws a ReferenceError because let is not initialized until its declaration is evaluated - this is the Temporal Dead Zone (TDZ).

Reference: MDN hoisting and TDZ: https://developer.mozilla.org/en-US/docs/Glossary/Hoisting

Example D - this binding and arrow functions

Consider:

const obj = {
  value: 42,
  regular() {
    return this.value;
  },
  arrow: () => this.value,
};

console.log(obj.regular()); // ?
console.log(obj.arrow()); // ?

Answer

  • obj.regular() -> 42. A regular method’s this is the calling object.
  • obj.arrow() -> depends on surrounding scope; arrow functions don’t have their own this and close over the this value of the surrounding lexical environment (often window or undefined in modules). So usually it won’t be 42.

Reference: MDN this and arrow functions: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions

Example E - microtasks vs macrotasks (Promises vs setTimeout)

What order do these run?

console.log('script start');

setTimeout(() => console.log('timeout'), 0);

Promise.resolve().then(() => console.log('promise'));

console.log('script end');

Output and explanation

  • script start
  • script end
  • promise
  • timeout

Why: Promise callbacks (microtasks) run before the next macrotask (the setTimeout callback). See MDN for microtask/macrotask explanation: https://developer.mozilla.org/en-US/docs/Web/API/EventLoop#microtasks_and_macrotasks

Advanced: tricky interview prompts and robust answers

  1. “Write a simple debounce function”

A good answer is short, correct, and explains edge cases (leading/trailing options, immediate invocation, cancelation). Example:

function debounce(fn, wait = 0) {
  let timer = null;
  return function (...args) {
    clearTimeout(timer);
    timer = setTimeout(() => fn.apply(this, args), wait);
  };
}

Explain: This cancels previous scheduled call and schedules a new one. Mention how you’d add cancel or leading/trailing behavior.

  1. “Deep clone an object (simple)”

Be explicit about limitations (functions, DOM nodes, circular refs). A simple solution:

function simpleClone(obj) {
  return JSON.parse(JSON.stringify(obj));
}

Then explain pitfalls: loses non-JSON types, Dates, RegExps, functions, and fails on circular references - so explain when you’d use a structured clone (browser API) or write a recursive algorithm.

  1. “Why is typeof null === ‘object’?”

Explain the historical reason and emphasize compatibility. Point to the MDN typeof page: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/typeof

  1. “new behavior and returned values”

Question: what happens if a constructor explicitly returns a primitive vs an object?

Example:

function Person(name) {
  this.name = name;
  return { name: 'other' };
}

const p = new Person('alice');
console.log(p.name); // 'other'

function Person2(name) {
  this.name = name;
  return 42;
}
const p2 = new Person2('bob');
console.log(p2.name); // 'bob'

Explain: If constructor returns an object, that object becomes the result of new. If it returns a primitive, this is returned.

Reference: MDN new operator: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/new

How to approach tricky questions in interviews (step-by-step)

  1. Slow down and clarify
  • Ask about the environment (browser vs Node), expected version, or constraints. Clarify ambiguous behavior.
  1. State assumptions and your plan
  • Say what you’ll assume and how you’ll proceed (walk execution, give a small demo, or write pseudocode).
  1. Break the problem into pieces
  • Identify the relevant JS features (closures, scope, types, event loop) and analyze them independently.
  1. Test edge cases out loud
  • What happens with null, undefined, empty arrays, 0, negative numbers, promises that reject? Interviewers value thoughtful checks.
  1. If stuck, suggest experiments
  • Propose quick REPL tests or mental simulations and explain what you’d expect and why.

Common clarifying phrases that help

  • “Do you mean Node or browser?”
  • “Should I assume ES6+ features are allowed?”
  • “Do you want a fully production-ready implementation, or a first-pass approach and then improvements?”

Practice resources (official docs and interactive sites)

Closing: mindset over memorization

Tricky JavaScript questions are opportunities to demonstrate reasoning, not to parrot obscure facts. Focus on:

  • Explaining assumptions
  • Breaking down the program execution
  • Showing how to test and validate your ideas

If you practice small snippets, read specification-backed explanations (MDN is great), and learn to communicate your thought process, “tricky” questions become manageable puzzles rather than traps.

Further reading

Good luck - and remember: interviewers usually want to see how you think, not whether you memorized a corner case.

Back to Blog

Related Posts

View All Posts »