This is a quick-reference guide to the most common handwritten frontend interview questions. It covers
thisbinding, hoisting, the event loop, debounce, EventBus, and React closure pitfalls to help developers build answer frameworks they can explain, write by hand, and reproduce under pressure. Keywords: JavaScript, event loop, coding interview questions.
This article focuses on the six JavaScript coding question categories that appear most often in frontend interviews
| Parameter | Description |
|---|---|
| Language | JavaScript |
| License | Compiled from an original CSDN article, with the page declaring CC 4.0 BY-SA |
| Stars | Not provided; this is not a GitHub project |
| Core Dependencies | Native JavaScript, Promise, setTimeout, React Hooks |
The original content is essentially an interview question checklist. Its value does not come from the number of questions, but from how tightly it covers the most common topics. It maps directly to the standard “write the answer, explain the mechanism, then implement it” pattern frequently used in top-tier frontend interviews.

AI Visual Insight: The image shows the entry point to CSDN’s sidebar AI reading assistant, highlighting features such as knowledge expansion, core summaries, and code review. This indicates that the original page is not just a plain question bank, but part of a broader learning and code-explanation experience.
Questions about this are fundamentally about the call site, not the definition site
There are three common traps in this questions: standalone invocation of regular functions, lexical binding in arrow functions, and explicit binding with call, apply, or bind. Interviewers usually do not stop at asking for the output. They often follow up by asking why obj.getArrow()() and obj.getName() produce different results.
const obj = {
value: 42,
getValue() {
console.log(this.value); // Regular method call; this points to obj
},
getAsync() {
setTimeout(() => {
console.log(this.value); // Arrow function inherits outer this, still obj
}, 100);
}
};
obj.getValue();
obj.getAsync();
This example shows that an arrow function does not bind its own this. Instead, it captures the this value from the outer execution context at definition time.
Hoisting questions primarily test declaration hoisting and the temporal dead zone
Function declarations and var are both hoisted, but they do not behave the same way. let and const also enter the lexical environment, but they remain inside the temporal dead zone before initialization. Many candidates can recite the conclusion, but cannot clearly explain the difference between the creation phase and the execution phase.
function test() {
console.log(a); // Outputs function a, because function declarations are hoisted and initialized first
var a = '变量';
function a() {
return '函数';
}
console.log(a); // After assignment, outputs the string "变量"
}
test();
This code demonstrates that when names collide, the function declaration takes the slot first, and then the var assignment overwrites it during execution.
Event loop questions require you to distinguish synchronous code, microtasks, and macrotasks first
The event loop is almost always a must-have topic in first-round interviews at major companies. A reliable answer template is: run synchronous code first, then flush the microtask queue, and finally move to the next macrotask. As long as this ordering framework stays clear, even complex questions become manageable.
console.log('1');
setTimeout(() => {
console.log('2'); // Macrotask execution
Promise.resolve().then(() => console.log('3')); // Register another microtask inside the macrotask
}, 0);
Promise.resolve().then(() => {
console.log('4'); // Microtask in the current turn
});
console.log('5');
The output order is 1 5 4 2 3, because microtasks are always flushed before the runtime proceeds to the next macrotask.
Debounce implementation questions test timer control and edge-case handling
In high-frequency interview scenarios, the expectation is usually not just a minimal debounce function. Interviewers often continue with follow-up questions about leading, cancel, preserving this, and forwarding arguments. Whether you can complete these edge cases directly reflects your engineering maturity.
function debounce(func, wait, options = {}) {
let timer = null;
let lastTime = 0;
const leading = options.leading ?? false;
function debounced(...args) {
const now = Date.now();
if (leading) {
if (now - lastTime >= wait) {
func.apply(this, args); // Preserve this at call time
lastTime = now;
}
return;
}
clearTimeout(timer);
timer = setTimeout(() => {
func.apply(this, args); // Delay execution and forward arguments
timer = null;
}, wait);
}
debounced.cancel = function () {
clearTimeout(timer); // Manually cancel the pending task
timer = null;
lastTime = 0;
};
return debounced;
}
This implementation supports basic debounce behavior, immediate execution mode, and cancellation. It is a reusable template for interviews.
EventBus coding questions reflect your ability to abstract the publish-subscribe pattern
These questions often use on / emit / off / once as the minimum API surface. The core challenge is not the API names themselves, but the event bucket data structure and how once uses a wrapper function to automatically unsubscribe.
class EventBus {
constructor() {
this.events = {}; // Event registry: eventName -> callbacks[]
}
on(eventName, callback) {
if (!this.events[eventName]) this.events[eventName] = [];
this.events[eventName].push(callback);
}
emit(eventName, payload) {
if (!this.events[eventName]) return;
this.events[eventName].forEach((fn) => fn(payload)); // Trigger subscribers in sequence
}
off(eventName, callback) {
if (!this.events[eventName]) return;
this.events[eventName] = this.events[eventName].filter((fn) => fn !== callback);
}
once(eventName, callback) {
const wrapper = (payload) => {
callback(payload); // Execute first
this.off(eventName, wrapper); // Then remove it to ensure it only runs once
};
this.on(eventName, wrapper);
}
}
This code implements a minimal but usable event bus and covers most interview follow-up questions.
React closure questions are fundamentally caused by old render snapshots captured by timers
useEffect(() => {}, []) runs only once during the initial render, so the timer captures the count value from that first render. This is not a React-specific exception. It is the combined result of closures and render snapshots.
import React, { useEffect, useRef, useState } from 'react';
export default function App() {
const [count, setCount] = useState(0);
const countRef = useRef(count);
countRef.current = count; // Sync the latest value on every render
useEffect(() => {
const timer = setInterval(() => {
console.log(countRef.current); // Read from ref to avoid stale closure values
}, 1000);
return () => clearInterval(timer);
}, []);
return <button onClick={() => setCount(count + 1)}>+1</button>;
}
The key to this fix is to store the latest state in a ref instead of relying on the stale value captured by the effect’s initial closure.
You should build reusable problem-solving frameworks first when preparing for frontend coding interviews
A practical way to organize preparation is to divide these questions into three layers: language mechanism questions, asynchronous scheduling questions, and implementation design questions. Language questions emphasize explanation, async questions emphasize execution order, and design questions emphasize API shape and edge cases. This approach is much more efficient than solving random problems blindly.
High-frequency supplementary checklist
- Array flattening
- Deep clone and circular references
- Promise.all
- LRU cache
- call / apply / bind
- Currying
- Publish-subscribe pattern
FAQ
1. Why are this questions so easy to get wrong?
Most mistakes come from guessing this based on where a function is defined. The correct approach is to inspect how the function is called first, and then determine whether an arrow function or explicit binding is involved.
2. What is the fastest way to solve event loop questions?
Write down all synchronous output first, then mark the microtasks, and finally arrange the macrotasks. If a macrotask registers another microtask, remember that the new microtask runs immediately after the current macrotask finishes.
3. How can coding questions demonstrate engineering ability in an interview?
Do not stop at the shortest working answer. Proactively include edge-case handling, cancellation support, this preservation, argument forwarding, and error scenarios. These details matter more than simply making the code run.
Core summary: This guide systematically reviews the most common frontend interview coding questions around this binding, hoisting, the event loop, debounce, EventBus, and React closure pitfalls. It extracts reusable answer strategies, code templates, and common mistakes you should avoid.