Rigorous exam preparation for practical and theoretical evaluations.
This section contains rigorous, logic-based, and theoretical questions designed specifically for your Viva Voce based on your exact JavaScript and React syllabus. Use the dropdowns to test yourself!
var: Function-scoped. Can be redeclared and reassigned. It is hoisted and initialized with undefined.let: Block-scoped ({}). Cannot be redeclared in the same scope, but can be reassigned. Hoisted but sits in the "Temporal Dead Zone" until execution reaches it.const: Block-scoped. Cannot be redeclared or reassigned. Must be initialized at the time of declaration. (Note: For objects/arrays, the reference is constant, but the contents can be mutated).Hoisting is JavaScript's default behavior of moving variable and function declarations to the top of their respective scopes during the compilation phase, before execution.
var declarations are hoisted and initialized as undefined.let and const are hoisted but remain uninitialized (in the Temporal Dead Zone), resulting in a ReferenceError if accessed early.A Closure is when a function "remembers" its lexical environment (the variables around it) even after the parent function has finished executing.
Analogy: A closure is like a "backpack" that a function carries. Even when the function moves away from its home (parent scope), it still has its backpack full of local variables.
function createGreeting(greeting) {
return function(name) {
console.log(greeting + ", " + name);
};
}
const sayHello = createGreeting("Hello");
// 'createGreeting' has finished, but 'sayHello' still remembers "Hello"!
sayHello("Alice"); // "Hello, Alice"
Viva Tip: Mention that closures are the foundation for Data Privacy (private variables) and Currying.
A Higher-Order Function is a function that does at least one of the following:
map, filter, reduce).This is about Type Coercion.
== (Abstract Equality): Compares only values. If types are different, JS converts them to the same type first. 5 == '5' // true.=== (Strict Equality): Compares both value AND type. No conversion happens. 5 === '5' // false.Example: 0 == false // true (coercion), but 0 === false // false (different types).
Regular functions define their own this context based on how they are called (e.g., the object calling the method).
Arrow functions do not have their own this binding. Instead, they inherit this from their surrounding lexical scope at the time they are defined.
Synchronous: Blocking. Code waits for one line to finish before moving to the next.
Asynchronous: Non-blocking. Code starts a task (like an API call) and continues to the next line while the task runs in the background.
Analogy (The Coffee Shop):
Sync: You stand at the counter and wait until your coffee is ready before the next person can order. The whole line is blocked.
Async: You order, get a pager (Promise), and sit down. The barista takes the next order immediately. They beep your pager when your coffee is ready.
JavaScript is single-threaded. The Event Loop is the mechanism that allows it to be non-blocking.
The Execution Trace:
Example: Even setTimeout(0) will wait for ALL sync code to finish because the Event Loop only checks the queue when the Stack is completely empty.
console.log("Start");
setTimeout(() => console.log("Timeout"), 0);
Promise.resolve().then(() => console.log("Promise"));
console.log("End");
Output: Start, End, Promise, Timeout
Why?
1. Start and End are sync.
2. Microtasks (Promises) have higher priority than Macrotasks (setTimeout). The Event Loop clears the Microtask queue completely before looking at the Macrotask queue.
The Real DOM is heavy and slow to update. The Virtual DOM is a lightweight JS object that is a "copy" of the Real DOM.
The 3-Step Process:
Analogy: If you want to change a room's wallpaper, you don't demolish the whole house and rebuild it (Real DOM update). You just change the blueprint (Virtual DOM), see that only one wall is different, and then go paint only that wall (Reconciliation).
An SPA loads a single HTML page upfront (index.html). Instead of requesting a new HTML page from the server every time you click a link, JavaScript dynamically rewrites the content on the current page. React Router is used to intercept URL changes and swap components without refreshing the page.
JSX is a syntax extension that allows us to write HTML-like markup inside JavaScript. Browsers cannot understand JSX directly.
Babel is a JavaScript compiler that converts JSX into plain React.createElement() JavaScript function calls that the browser can execute.
class and this keywords, use lifecycle methods (componentDidMount, render), and maintain state via this.state.useState, useEffect) for state and lifecycles, and generally offer better performance as they are pure JavaScript functions without the overhead of class instances.Analogy: A car.
State: The fuel level and speed (changes as the car moves).
Props: The color and brand (stays the same regardless of how fast you drive).
React uses Reference Comparison to check if an object has changed.
If you do user.name = "Bob", the object's memory address remains the same. React thinks "nothing changed" and skips the re-render.
The Fix: Use the spread operator {...user} to create a new memory reference. This forces React to recognize the change and update the UI.
Prop Drilling: Passing data through 10 components that don't need it, just to reach a child at the bottom. This makes code hard to maintain.
Context API: A global "Radio Station".
The Parent "Broadcasts" (Provider) the data.
The Child "Tunes in" (useContext) directly.
Intermediate components don't hear a thing and don't need to pass any props.
useEffect is where we handle "Side Effects" (API calls, subscriptions, timers).
The Dependency Array [ ]:
[ ] (Empty): Runs once after the component is born (Mount). Perfect for API calls.[state]: Runs on mount AND whenever state changes.Cleanup Function: If you return a function inside useEffect, React runs it when the component "dies" (Unmount). Used to stop timers or cancel API requests.
1. Only call Hooks at the Top Level: Don't call them in loops, conditions, or nested functions.
2. Only call Hooks from React Functions: Or from your own custom hooks.
The "WHY": React relies on the Order of Hook Calls. Internally, React stores state in an array. If you put a hook inside an if statement, the order might change on the next render, and React will get confused about which state belongs to which hook.
useState: Triggers a component re-render when the state value changes. Used for data that affects the UI.useRef: Does not trigger a re-render when its .current value changes. Used to store mutable values across renders (like timer IDs) or to directly access real DOM elements.Both are used for Performance Optimization:
useMemo: Caches (memoizes) the result of an expensive calculation so it doesn't run on every render unless its dependencies change.useCallback: Caches a function definition so that a new function reference isn't created on every render, preventing unnecessary re-renders of child components that receive the function as a prop.React.memo: Prevents a whole component from re-rendering. It "remembers" the output for specific props.
useMemo: Prevents a calculation from running again. It "remembers" the result of a math problem or filter logic.
Example: If your OS Desktop re-renders, use React.memo on the Icon components so they don't all re-draw every time the clock updates.
Fetch: Two-step process.
fetch(url)
.then(res => res.json()) // Step 1: Convert to JSON
.then(data => console.log(data)); // Step 2: Use data
Axios: One-step process.
axios.get(url)
.then(res => console.log(res.data)); // JSON is auto-converted
Major Difference: Axios automatically throws an error for 404/500 statuses, while Fetch only rejects the promise if the network fails.
BrowserRouter: Wraps the app and enables HTML5 history API tracking.Routes: A container that looks through all its child Route components to find the best match for the current URL.Route: Defines a specific path and the Component that should be rendered when that path is active (<Route path="/about" element={<About />} />).Link: Used instead of <a> tags to navigate without causing a page refresh.Redux Toolkit (RTK) is the official, recommended way to write Redux logic. It simplifies state management with centralized "slices" and a global store. Differences:
Both are Redux middlewares used to handle asynchronous side effects (like API calls).
yield). Great for highly complex async flows (like race conditions, cancelling requests, or debouncing).Prepare to absolutely destroy the examiner with these deep-dive questions.
Unlike class-based languages (like Java), JavaScript objects inherit directly from other objects via an internal link called the [[Prototype]] (accessible via __proto__). When you try to access a property on an object, JavaScript searches the object itself. If it doesn't find it, it traverses up the "Prototype Chain" to its parent, then its grandparent, all the way until it hits null.
All three are used to explicitly set the this context for a function:
call(thisContext, arg1, arg2): Invokes the function immediately. Arguments are passed individually.apply(thisContext, [arg1, arg2]): Invokes the function immediately. Arguments are passed as an array.bind(thisContext, arg1, arg2): Does not invoke the function immediately. It returns a new function with the this keyword permanently bound.Instead of attaching an event listener to 1,000 individual list items (<li>), you attach a single event listener to their parent (<ul>). Because events bubble up the DOM tree in JavaScript, the parent can catch events triggered by its children. You then check event.target to see exactly which child was clicked. This saves massive amounts of memory.
function Counter() {
const [count, setCount] = useState(0);
useEffect(() => {
const timer = setInterval(() => {
console.log(count);
}, 1000);
return () => clearInterval(timer);
}, []); // Empty dependency array
return <button onClick={() => setCount(c => c + 1)}>Increment</button>;
}
Q: What happens if the user clicks increment 5 times? What prints to the console?
A: The console will print 0 every second, infinitely.
Why? Because the useEffect has an empty dependency array ([]), the closure inside the interval only captures the state value from the first render, where count was 0. It is "stale." To fix it, you must add count to the dependency array.
Introduced in React 16, Fiber is a complete rewrite of React's core reconciliation algorithm. Older React (Stack Reconciler) performed updates synchronously, which could lock up the main thread during heavy rendering. Fiber allows rendering to be interruptible. React can pause an ongoing render, yield control to the browser to handle high-priority tasks (like user typing or animations), and then resume rendering where it left off.
When you write onClick in React, you are not actually interacting with the browser's native click event. React wraps the native browser event in a cross-browser wrapper called a SyntheticEvent. This ensures that the event behaves identically across all browsers (Chrome, Firefox, Safari) and pools events for performance optimization.
useLayoutEffect: Runs synchronously immediately after React has mutated the DOM but before the browser paints it to the screen. Use this only when you need to read the DOM layout (like measuring an element's width) and re-render synchronously to prevent screen flickering.This is because of Strict Mode (<React.StrictMode>). It intentionally double-renders components to help developers find side-effects and bugs (like improper state mutations or missing cleanups) that might otherwise go unnoticed.
CORS (Cross-Origin Resource Sharing) is a security feature. If your React app (localhost:5173) tries to talk to an API (localhost:5000), the browser blocks it unless the server explicitly allows it.
Solution: On the backend, use the cors middleware, or in Vite/React, use a Proxy in your configuration.
I used the React Developer Tools browser extension to inspect component props/state and the Console Tab with useEffect logs to track when re-renders were happening.
Specific questions about your capstone architecture that examiners love to ask.
The Terminal uses String Parsing Logic. When the user hits Enter, the input string is split into command and arguments. I then use a matching logic to map those strings to specific JavaScript functions (e.g., ls() or mkdir()) defined in the FileSystem Context.
The VFS is a Nested JavaScript Object that mimics a directory tree. It is managed via React Context API to ensure that every app (File Explorer, Terminal, Notes) has a synchronized "Real-time" view of the files without needing a backend database.
Using Context API avoids Prop Drilling. Since the File System and Theme settings are needed by almost every component in the OS, providing them via a Context Provider makes the data globally accessible and keeps the component code much cleaner and easier to maintain.
Each app is wrapped in an OSWindow component. I manage the window's visibility via React Routing. The active window can be brought to the front using CSS z-index, though in this simplified version, the router handles focus by mounting/unmounting apps in the workspace area.