JavaScript & React Interview Questions and Answers

A growing, hand-picked set of JavaScript and React.js interview questions with clear, example-driven answers. Use it to prepare for frontend developer interviews and to sharpen your day-to-day coding. Tap any question to reveal the answer.

10 questionsJavaScriptReact.jsPractice in the JS Compiler →

JavaScript Questions

JS

Explain the difference between var, let, and const. Touch on scope and hoisting.

Scope

var is function-scoped. It is visible throughout the entire function it is declared in, ignoring block boundaries like if or for. let and const are block-scoped — they only exist inside the nearest { } block.

js
function test() {
  if (true) {
    var a = 1;
    let b = 2;
  }
  console.log(a); // 1
  console.log(b); // ReferenceError
}

Hoisting

All three are hoisted (conceptually moved to the top of their scope), but they behave differently. var is hoisted and initialized to undefined, so you can reference it before its declaration without an error — you just get undefined. let and const are hoisted but not initialized. They sit in the Temporal Dead Zone (TDZ) from the start of the block until the declaration line; accessing them there throws a ReferenceError.

js
console.log(x); // undefined
var x = 5;

console.log(y); // ReferenceError (TDZ)
let y = 5;

Reassignment

var and let can be reassigned. const cannot. But note: const only prevents reassignment of the binding, not mutation. A const object's properties can still change.

js
const obj = { name: "Satyam" };
obj.name = "Changed"; // allowed
obj = {};             // TypeError

The one-liner interviewers like: "Use const by default, let when you need to reassign, and avoid var because its function-scoping and hoisting-to-undefined cause bugs."

JS

What is the difference between == and ===?

== is loose equality: it converts the operands to the same type before comparing. === is strict equality: it compares both value and type, with no conversion.

js
1 == "1"    // true  (string "1" coerced to number 1)
1 === "1"   // false (number vs string)
0 == false  // true  (both coerce to 0)
0 === false // false (number vs boolean)
null == undefined  // true
null === undefined // false

Rule of thumb: always use === (and !==) to avoid surprising type-coercion bugs.

JS

What is a closure? Give a practical use.

A closure is a function that remembers and keeps access to variables from the scope where it was created, even after that outer function has finished running. It is how JavaScript supports private state and function factories.

js
function makeCounter() {
  let count = 0;               // private to the closure
  return function () {
    count++;
    return count;
  };
}

const next = makeCounter();
console.log(next()); // 1
console.log(next()); // 2
// 'count' is not accessible from outside — it's encapsulated.

Closures power things like memoization, debouncing, event handlers, and the module pattern.

JS

How does the event loop handle async code? What prints first?

JavaScript runs on a single thread with a call stack. Async work (timers, fetch, promises) is handed to the environment, and its callback is queued. The event loop only pushes a queued callback onto the stack when the stack is empty. Microtasks (promise .then/await callbacks) run before macrotasks (setTimeout).

js
console.log("1: sync");

setTimeout(() => console.log("2: timeout"), 0);

Promise.resolve().then(() => console.log("3: promise"));

console.log("4: sync");

// Output order:
// 1: sync
// 4: sync
// 3: promise   (microtask — runs before the timer)
// 2: timeout   (macrotask)

React.js Questions

React

What is the Virtual DOM and how does reconciliation work?

The Virtual DOM is a lightweight in-memory JavaScript representation of the UI. When state changes, React builds a new Virtual DOM tree, diffs it against the previous one (a process called reconciliation), and then updates only the real DOM nodes that actually changed.

Direct DOM manipulation is slow; batching and applying the minimal set of changes is why React updates are efficient. The key prop helps React match items between renders during this diff.

React

What is useEffect and how does the dependency array work?

useEffect runs side effects (data fetching, subscriptions, timers, manual DOM work) after the render is painted. The dependency array controls when it re-runs:

js
useEffect(() => {
  // runs after EVERY render
});

useEffect(() => {
  // runs ONCE on mount
}, []);

useEffect(() => {
  // runs on mount + whenever 'userId' changes
  fetchUser(userId);

  return () => {
    // cleanup: runs before the next effect and on unmount
    cancelFetch();
  };
}, [userId]);

Always list every value from props/state used inside the effect in the dependency array, or you risk stale data.

React

Why does React need a key when rendering lists?

key gives each list item a stable identity so React can match items between renders and update, move, or remove only what changed — instead of re-creating the whole list.

js
// Good: stable, unique id from your data
{users.map((u) => <li key={u.id}>{u.name}</li>)}

// Risky: index breaks when the list reorders/inserts/deletes
{users.map((u, i) => <li key={i}>{u.name}</li>)}

Avoid the array index as a key for lists that can reorder or change length — it leads to wrong state and DOM reuse.

React

What is the difference between useMemo and useCallback?

Both memoize between renders to avoid unnecessary work. useMemo caches a computed value; useCallback caches a function reference.

js
// Caches the RESULT of an expensive calculation
const total = useMemo(() => heavyCompute(items), [items]);

// Caches the FUNCTION so its reference stays stable
const handleClick = useCallback(() => save(id), [id]);

// useCallback(fn, deps) === useMemo(() => fn, deps)

Use them to keep referential equality stable, e.g. when passing props to a React.memo child — not on everything, since memoization has its own cost.

React

Controlled vs uncontrolled components — what's the difference?

In a controlled component the input's value is driven by React state via onChange, so React is the single source of truth. In an uncontrolled component the DOM holds the value and you read it with a ref.

js
// Controlled
const [name, setName] = useState("");
<input value={name} onChange={(e) => setName(e.target.value)} />

// Uncontrolled
const ref = useRef();
<input ref={ref} defaultValue="Satyam" />
// read it later with ref.current.value

Prefer controlled inputs for validation and dynamic UI; uncontrolled is fine for simple or non-React forms.

React

What is the difference between props and state?

Props are inputs passed into a component by its parent and are read-only inside that component. State is data owned by a component that can change over time (via useState/useReducer) and triggers a re-render when updated.

js
function Welcome({ name }) {        // 'name' is a prop (read-only)
  const [count, setCount] = useState(0); // 'count' is state
  return (
    <button onClick={() => setCount(count + 1)}>
      {name} clicked {count} times
    </button>
  );
}

Props flow down from parent to child; state is local unless you "lift it up" to share between siblings.

© 2026 Satyam Modi. Interview prep for frontend developers.