Ola Frontend Interview Questions
JavaScript and React fundamentals with a build round.
Ola's products include ride hailing, electric vehicles and financial services, with customer-facing web flows and many internal dashboards. Frontend interviews are usually described as fundamentals-driven and practical.
Expect JavaScript concept and output questions, React basics, a machine coding exercise and some problem solving.
- Questions
- 15, 5 with free answers
- Interview rounds
- 5
- Last reviewed
- October 2026
Ola frontend interview process
The usual shape of the loop. A guide to what to prepare, not a promise of what you will get.
- 1
JavaScript fundamentals
Hoisting, closures,
this, promises and output-based snippets. - 2
Machine coding
Build a small UI such as a search box, a modal or a grid game in about an hour.
- 3
React and browser round
Hooks, forms, refs, storage, CORS and CSS layout.
- 4
Problem solving
Basic data structure and algorithm questions.
- 5
Hiring manager
Project discussion and team fit.
What interviewers tend to look for
- Core JavaScript, explained and demonstrated on small snippets.
- Getting a working UI on screen quickly.
- Live status updates, as in tracking a ride.
- CSS layout and responsive behaviour.
Your Ola mock interview
15 questions. Type an answer under each one and an AI reviewer scores it and tells you what you missed. Stuck on one? Ask for a hint. A free account gets 3 AI replies a day.
Your mock interview
0 of 15 answered
Answer a question and your score shows up here.
JavaScript
6 questions- Question 1 of 15JavaScript
Ola interviewer
What is a closure? Give a practical use for one.
Model answer
A closure is a function together with the scope it was created in. The function keeps access to the variables of that scope even after the outer function has returned.
function createCounter() { let count = 0; // private: nothing outside can touch it return { increment: () => ++count, value: () => count, }; } const counter = createCounter(); counter.increment(); counter.value(); // 1Practical uses: private state as above, function factories, and utilities such as
debounceandmemoize, which keep a timer or a cache between calls.The cost to mention: a closure keeps its captured variables alive for as long as the function is reachable, so a long-lived callback holding a large object is a memory leak.
- Question 2 of 15JavaScript
Ola interviewer
Explain hoisting and the temporal dead zone.
Model answer
Declarations are registered when a scope is created, before any of its code runs. What differs is the starting value:
varis hoisted and set toundefined, so reading it early givesundefined.- Function declarations are hoisted with their body, so you can call them above where they are written.
let,constandclassare hoisted but left uninitialised. Reading them before the declaration line throws aReferenceError.
The stretch between the start of the scope and the declaration line is the temporal dead zone.
console.log(a); // undefined console.log(b); // ReferenceError var a = 1; let b = 2;Function expressions follow their variable:
var fn = function () {}isundefineduntil that line runs. - Question 3 of 15JavaScript
Ola interviewer
How is the value of
thisdecided? How do call, apply and bind differ?Model answer
thisdepends on how a function is called, not where it is written:- Called as a method (
user.greet()): the object before the dot. - Called plainly (
greet()):undefinedin strict mode and in modules, the global object otherwise. - Called with
new: the newly created object. - Called with
call,applyorbind: whatever you pass. - Arrow functions have no
thisof their own. They use the one from the surrounding scope, and it cannot be rebound.
callinvokes the function with arguments listed one by one,applytakes them as an array, andbinddoes not invoke anything: it returns a new function withthis(and optionally leading arguments) fixed.The classic bug is passing
user.greetas a callback. The function is then called plainly and loses itsthis. - Called as a method (
- Question 4 of 15JavaScript
Ola interviewer
What is the difference between debounce and throttle? Implement debounce.
Model answer
Debounce waits until the calls stop for a set time, then runs once. Use it for a search box or for saving after the user stops typing. Throttle runs at most once per interval while the calls keep coming. Use it for scroll, resize and drag handlers.
function debounce(fn, wait) { let timer; return function (...args) { clearTimeout(timer); timer = setTimeout(() => fn.apply(this, args), wait); }; }Common follow-ups: keep
thisand the arguments (done above), add acancelmethod, add aleadingoption that fires on the first call, and then write throttle. - Question 5 of 15JavaScript
Ola interviewer
What does a setTimeout inside a
for (var i ...)loop print, and how do you fix it?Model answer
for (var i = 0; i < 3; i++) { setTimeout(() => console.log(i), 0); } // 3, 3, 3varis function-scoped, so there is oneishared by all three callbacks. They run after the loop has finished, wheniis already 3.Fixes, in the order you would reach for them:
- Use
let. It creates a new binding for each iteration, so the output is 0, 1, 2. - Pass the value in:
setTimeout((n) => console.log(n), 0, i). - Wrap the body in an immediately invoked function that takes
ias a parameter. This is the pre-ES6 answer.
- Use
- Question 6 of 15JavaScript
Ola interviewer
Write a polyfill for Array.prototype.reduce.
Model answer
Array.prototype.myReduce = function (callback, initialValue) { let index = 0; let accumulator = initialValue; if (arguments.length < 2) { // No initial value: use the first element that exists. while (index < this.length && !(index in this)) index++; if (index >= this.length) { throw new TypeError('Reduce of empty array with no initial value'); } accumulator = this[index++]; } for (; index < this.length; index++) { if (index in this) { accumulator = callback(accumulator, this[index], index, this); } } return accumulator; };The details that separate answers: checking
arguments.lengthinstead ofinitialValue === undefined(passingundefinedon purpose is valid), throwing on an empty array with no initial value, and skipping holes in sparse arrays.mapandfilterare the usual warm-ups. Both take the same(value, index, array)callback and an optionalthisArg.
TypeScript
1 question- Question 7 of 15TypeScript
Ola interviewer
What is the difference between a type alias and an interface?
Model answer
Both can describe the shape of an object, and for that job they are close to interchangeable. The differences:
- An
interfacecan be declared more than once and the declarations merge. That is how you add a field toWindowor to a library's types. - An
interfaceextends others withextends. Atypecombines with&. - A
typecan name anything: unions, tuples, primitives, mapped types and conditional types. An interface can only describe an object or function shape.
type Status = 'idle' | 'loading' | 'error'; // only a type can do this interface User { id: string; name: string; } interface Admin extends User { permissions: string[]; }A sensible rule to state: use either for object shapes, use
typewhen you need a union or a computed type, and stay consistent within a codebase. - An
React
3 questions- Question 8 of 15React
Ola interviewer
What is the difference between a controlled and an uncontrolled component?
Model answer
In a controlled input, React state holds the value. You pass
valueandonChange, and every keystroke goes through state. That makes validation, formatting and conditional UI easy.In an uncontrolled input, the DOM holds the value. You give it a
defaultValueand read the result on submit, through a ref orFormData.// Controlled <input value={email} onChange={(e) => setEmail(e.target.value)} /> // Uncontrolled <form onSubmit={(event) => { event.preventDefault(); const data = new FormData(event.currentTarget); save(data.get('email')); }} > <input name="email" defaultValue="" /> </form>Uncontrolled inputs re-render less, which is why form libraries such as React Hook Form use them, and React 19 form actions work the same way. A file input is always uncontrolled.
The warning to recognise: an input whose
valuegoes fromundefinedto a string has switched from uncontrolled to controlled. Start it with an empty string. - Question 9 of 15React
Ola interviewer
How does useEffect work? Explain the dependency array, cleanup and the common mistakes.
Model answer
An effect runs after React has committed a render. Its job is to keep something outside React in step with your state: a subscription, a timer, a DOM API or a network request.
- No dependency array: runs after every render.
- An empty array: runs once after the first render.
- With dependencies: runs again when any of them changes, compared with
Object.is. - The function you return is the cleanup. It runs before the next run of the effect and when the component unmounts.
useEffect(() => { const controller = new AbortController(); fetch('/api/users/' + id, { signal: controller.signal }) .then((response) => response.json()) .then(setUser) .catch((error) => { if (error.name !== 'AbortError') setError(error); }); return () => controller.abort(); }, [id]);Mistakes interviewers look for: leaving a dependency out and reading a stale value, depending on an object or function that is recreated every render (an endless loop), not handling a response that arrives after
idhas changed, and using an effect to compute something from props that could be computed during render.In development, Strict Mode mounts each component, unmounts it and mounts it again, to expose effects that do not clean up.
- Question 10 of 15React
Ola interviewer
What is useRef for? How do you pass a ref to a child component?
Model answer
useRefreturns an object with acurrentproperty that stays the same between renders. Changingcurrentdoes not cause a re-render. Two uses:- Reaching a DOM node, to focus it, measure it or scroll to it.
- Keeping a value that should survive renders but is not shown: a timer id, the previous value of a prop, the latest version of a callback.
Do not read or write
currentwhile rendering. Use it in effects and event handlers.function TextField({ ref, ...props }) { return <input ref={ref} {...props} />; } function Form() { const inputRef = useRef(null); return ( <> <TextField ref={inputRef} /> <button onClick={() => inputRef.current?.focus()}>Edit</button> </> ); }In React 19,
refis an ordinary prop on function components, as above. In React 18 and earlier the child has to be wrapped inforwardRef.useImperativeHandlelets a component expose a small API, such asopen()andclose(), instead of its DOM node.
CSS
2 questions- Question 11 of 15CSS
Ola interviewer
Explain the CSS box model and box-sizing.
Model answer
Every element is a box made of four layers: content, padding, border and margin.
box-sizingdecides whatwidthandheightmeasure. With the default,content-box, they set the content area only, so a 200px wide box with 20px padding and a 1px border takes 242px. Withborder-box, the padding and border are included in the 200px. That is easier to reason about, which is why most projects start with:*, *::before, *::after { box-sizing: border-box; }Related points that get asked:
- Vertical margins of adjacent block elements collapse into the larger of the two. This does not happen inside flex or grid containers.
- Inline elements ignore
width,heightand vertical margins.inline-blockaccepts them. outlineis drawn outside the border and does not take up space.
- Question 12 of 15CSS
Ola interviewer
How many ways can you centre an element horizontally and vertically?
Model answer
/* 1. Grid: the shortest */ .parent { display: grid; place-items: center; } /* 2. Flexbox */ .parent { display: flex; justify-content: center; align-items: center; } /* 3. Absolute positioning, size unknown */ .child { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); } /* 4. Absolute positioning with auto margins, size known */ .child { position: absolute; inset: 0; margin: auto; width: 200px; height: 100px; }Interviewers usually want you to explain one of them. In the third,
topandleftmove the child's corner to the middle of the parent, and the transform shifts it back by half of its own size, because percentages intranslaterefer to the element itself.For horizontal centring only:
margin-inline: autoon a block with a width, ortext-align: centerfor inline content.
Browser, performance and system design
1 question- Question 13 of 15Browser, performance and system design
Ola interviewer
Compare cookies, localStorage and sessionStorage. Where should an auth token be stored?
Model answer
- Cookies: about 4 KB each, sent to the server with every request to their domain. They can have an expiry and security flags.
- localStorage: around 5 MB per origin, kept until cleared, shared by all tabs. Never sent to the server. The API is synchronous.
- sessionStorage: the same API, limited to one tab and cleared when it closes.
- IndexedDB: a larger, asynchronous database for structured data, used for offline apps.
For a session or auth token, the safest common choice is a cookie with three flags:
HttpOnly: JavaScript cannot read it, so a script injected through XSS cannot steal it.Secure: sent over HTTPS only.SameSite=LaxorStrict: not sent on most cross-site requests, which blocks most CSRF.
Anything in
localStoragecan be read by any script running on the page, including a compromised dependency. That is why long-lived tokens do not belong there. If a design does keep a token in JavaScript, keep it in memory and make it short-lived, with the refresh token in an HttpOnly cookie.
Machine coding
2 questions- Question 14 of 15Machine coding
Ola interviewer
Build an accessible modal dialog.
Model answer
- Render it through a portal into
document.body, so that a parent'soverflowor stacking context cannot clip it. - The parent owns the
openstate and passesonClose. - Close on the Escape key, on a click on the backdrop and on the close button. A click inside the dialog must not close it.
- On open, move focus into the dialog. While it is open, Tab and Shift+Tab must cycle inside it. On close, return focus to the element that opened it.
- Stop the page behind from scrolling while it is open.
- Mark it up with
role="dialog",aria-modal="true"andaria-labelledbypointing at its title.
function Modal({ open, onClose, title, children }) { const ref = useRef(null); useEffect(() => { const dialog = ref.current; if (open && !dialog.open) dialog.showModal(); if (!open && dialog.open) dialog.close(); }, [open]); return ( <dialog ref={ref} onClose={onClose} aria-labelledby="modal-title"> <h2 id="modal-title">{title}</h2> {children} <button onClick={onClose}>Close</button> </dialog> ); }The native
dialogelement withshowModal()gives you the focus trap, Escape handling, the backdrop and the top layer for free. Mention it even if the interviewer wants the manual version, and be ready to write the focus trap by hand. - Render it through a portal into
- Question 15 of 15Machine coding
Ola interviewer
Build tic-tac-toe.
Model answer
Keep as little state as possible: an array of nine cells. Whose turn it is and who has won are both worked out from the board on every render, so they can never disagree with it.
const LINES = [ [0, 1, 2], [3, 4, 5], [6, 7, 8], // rows [0, 3, 6], [1, 4, 7], [2, 5, 8], // columns [0, 4, 8], [2, 4, 6], // diagonals ]; function getWinner(board) { for (const [a, b, c] of LINES) { if (board[a] && board[a] === board[b] && board[a] === board[c]) return board[a]; } return null; } function Game() { const [board, setBoard] = useState(Array(9).fill(null)); const moves = board.filter(Boolean).length; const player = moves % 2 === 0 ? 'X' : 'O'; const winner = getWinner(board); const draw = !winner && moves === 9; const play = (index) => { if (board[index] || winner) return; setBoard(board.map((cell, i) => (i === index ? player : cell))); }; }- Ignore clicks on a filled cell and after the game is over.
- Show whose turn it is, the winner or a draw, and a reset button.
- Cells are buttons, so the game works with the keyboard.
Follow-ups: an N by N board with K in a row to win (count outwards from the last move instead of listing lines), move history with undo, highlighting the winning line, and a computer opponent.
Practise for Ola
Reading answers is the easy half. These problems run in the browser against real tests.
