Skip to main content

Cars24

πŸš€ My Cars24 Frontend Engineer Interview Experience (2025) | Software Development Engineer 3 - Frontend

πŸ’Ό Position Applied: Software Development Engineer 3 – Frontend
🏒 Company: Cars24
πŸ“ Location: Bangalore [Remote/Hybrid Options Available]
πŸ’° Compensation: 25 LPA Fixed + 10 LPA ESOPs
🧠 Primary Skills: JavaScript, React, NextJs, TypeScript, Data Structures, Performance Optimization
🎯 Final Outcome: Received Offer (Did not join, got better offer from other firm)


🏒 About Cars24

CARS24 is an Indian multinational online used car marketplace headquartered in Gurgaon. The company is considered among the four major organised players in the used car segment in India. CARS24 operates at scale and requires a customer authentication system that matches that scale.


πŸš€ Round 1: JavaScript Fundamentals

πŸ•’ Duration: 60 minutes

In this round, I was tested on my core JavaScript knowledge through several output-based questions. Below are the key concepts and topics that were covered, along with some of the coding questions I faced.

1️⃣ Hoisting, let, var, const, and Temporal Dead Zone

πŸ“Œ Key Concepts:

  • Hoisting is JavaScript's default behavior of moving declarations (not initializations) to the top of their containing scope during compilation.
  • The var keyword is hoisted and initialized with undefined.
  • let and const are hoisted but are not initialized, leading to a "Temporal Dead Zone" (TDZ) where accessing them before their declaration results in a reference error.
  • TDZ: The period between entering the scope and the actual declaration of let and const variables, where accessing them causes an error.

πŸ’‘ JS Note:

console.log(a); // undefined (var is hoisted)
var a = 5;

console.log(b); // ReferenceError (TDZ with let/const)
let b = 10;

Code Block

2️⃣ call, bind, and apply Methods

πŸ“Œ Key Concepts:

  • call() and apply() invoke a function immediately with a specified this value. The difference is that call() takes arguments as individual parameters, whereas apply() takes an array.
  • bind() creates a new function with a specified this value and allows pre-setting arguments.

πŸ’‘ Polyfill for bind():

// 🌟 Polyfill for the bind() method
Function.prototype.myBind = function(context, ...args) {
    // πŸ‘¨β€πŸ’» Save reference to the original function
    const fn = this;

    // πŸ”„ Return a new function that, when called, applies the original function
    return function(...innerArgs) {
        // πŸ‘Œ Use apply() to set the correct `this` context and merge initial args with the inner arguments
        fn.apply(context, [...args, ...innerArgs]); // Combine pre-set arguments with the arguments passed when the function is called
    };
};

Code Block

πŸ“ JS Note:

  • call and apply are useful for method borrowing, where you use a method from one object on another object.
  • bind is essential when working with event handlers or callbacks to ensure the correct this context.

3️⃣ Debouncing vs Throttling

πŸ“Œ Key Concepts:

  • Debouncing: It ensures that a function is only executed after a specified amount of time has passed since the last invocation. Useful for scenarios like input validation or search bar suggestions.
  • Throttling: It limits the number of times a function can be executed over a specific period. Great for performance-heavy operations like scroll events or window resizing.

πŸ’‘ JS Note:

  • Debounce Example:
// πŸ›‘ Debounce Function to Limit Function Calls
function debounce(func, delay) {
    // ⏱️ Variable to store the timeout ID
    let timeout;

    // 🧩 Return a new function that wraps the original function
    return function(...args) {
        // 🚫 Clear the previous timeout to reset the timer
        clearTimeout(timeout);

        // πŸ•’ Set a new timeout to invoke the function after the specified delay
        timeout = setTimeout(() => {
            // πŸ‘¨β€πŸ’» Execute the original function with the provided arguments
            func(...args);
        }, delay);
    };
}

Code Block

  • Throttle Example:
// πŸ›‘ Throttle Function to Limit Frequent Function Calls
function throttle(func, limit) {
    // πŸ“… Store the time when the function was last called
    let lastTime;

    // πŸ”„ Return a new function that wraps the original function
    return function(...args) {
        // ⏳ Only invoke the function if the specified limit time has passed since the last call
        if (!lastTime || Date.now() - lastTime >= limit) {
            // πŸ‘¨β€πŸ’» Execute the original function with the provided arguments
            func(...args);
            // πŸ•’ Update the last time the function was invoked
            lastTime = Date.now();
        }
    };
}

Code Block

4️⃣ IIFE (Immediately Invoked Function Expression)

πŸ“Œ Key Concepts:

  • IIFE is a function that runs immediately after it is defined. It is used to create a local scope and avoid polluting the global namespace.
  • The this keyword behaves differently inside an IIFE when used with arrow functions.

πŸ“ Code Example:

const myObject = {
    abc: "bar",
    func() {
        const self = this;
        console.log(`outer func: this.abc = ${this.abc}`);
        console.log(`outer func: self.abc = ${self.abc}`);
        (function() {
            console.log(`inner func: this.abc = ${this.abc}`);
            console.log(`inner func: self.abc = ${self.abc}`);
        }());
    }
};
myObject.func();

Code Block

Expected Output:

outer func: this.abc = bar
outer func: self.abc = bar
inner func: this.abc = undefined
inner func: self.abc = bar

Code Block

πŸ’‘ JS Note:
In the IIFE, this refers to the global object (or undefined in strict mode), not myObject. However, self correctly points to myObject because it was set explicitly.

5️⃣ React Concepts

πŸ“Œ Key Concepts:

  • useEffect(): A hook that lets you perform side effects in function components. It replaces lifecycle methods like componentDidMount and componentDidUpdate.
  • useMemo(): Used to memoize expensive calculations and avoid unnecessary re-renders by caching results.
  • useCallback(): Memoizes functions to avoid unnecessary re-creations of functions between renders.
  • React.memo(): A higher-order component that prevents unnecessary re-renders of functional components by shallowly comparing props.

πŸ’‘ JS Note:
React hooks like useEffect, useMemo, and useCallback are essential for optimizing performance in large applications.

Interview Tip:

πŸ’‘ Be Prepared to Explain "Why": When discussing core concepts like hoisting, this, or React hooks, interviewers often want to hear your reasoning and understanding. Make sure you explain how these concepts impact performance and maintainability.


🧱 Round 2: Machine Coding Round

🧩 Grid Light Box Cells Problem

In this round, I was tasked with creating a lightbox grid system that simulates a toggle behavior in a 2D matrix. The requirements were as follows:

  • Each cell should be toggleable (on/off).
  • Clicking on a cell should also toggle the adjacent cells (up, down, left, right).
  • Handle edge cases like corner cells and cells on the grid's borders.

πŸ‘¨β€πŸ’» Expectations:

  • Code Quality: Writing clean, maintainable code.
  • State Management: Efficiently managing the state of the grid.
  • Reusable Components: Building modular and reusable components.
  • Edge Case Handling: Accounting for all edge cases, such as cells on the grid's edges and corners.
  • Clean UI & Interactivity: Ensuring the UI is responsive and intuitive.

Tip: Make sure you're familiar with DOM manipulation, useState, and React's rendering performance optimizations. The interviewer will closely examine how you structure your components.

Expected UI

🧠 Learnings & JavaScript Notes:

React State Management:
Managing state in a grid system can become complex, especially with multiple cell states. For better performance and cleaner code, consider using useReducer instead of useState for optimal state updates.

Example:

const [state, dispatch] = useReducer(reducer, initialState);

Memoization of Cells:
To avoid unnecessary re-renders of each grid cell, you can use React.memo. This ensures that a cell only re-renders when its state changes (e.g., toggled on/off).

Example:

const Cell = React.memo(({ isActive, onClick }) => {
  return <div className={isActive ? "active" : ""} onClick={onClick}></div>;
});

DOM Rendering Optimization:
When working with a large grid, it’s essential to minimize re-renders. Using React.memo ensures that only the cells whose state has changed are re-rendered.

Avoiding Unnecessary Updates:
Use useCallback to memoize functions passed as props, preventing unnecessary re-renders of child components.

Example:

const toggleCell = useCallback((index) => {
  // logic to toggle cell state
}, [gridState]);  // dependencies to ensure the callback only changes when needed

🧩 JS Code Snippet for Grid Cell:

// 🧩 Cell component - React.memo to prevent unnecessary re-renders
const Cell = React.memo(({ isActive, onClick }) => {
  return (
    <div 
      // 🌟 Dynamically applying the "active" class if the cell is active
      className={isActive ? "active" : ""} 
      
      // πŸ–±οΈ Handling cell click event to toggle the state
      onClick={onClick}
      
      // 🎨 Applying styles to change the background color based on the cell's state
      style={{
        width: '30px', 
        height: '30px', 
        backgroundColor: isActive ? 'yellow' : 'gray' 
      }}
    />
  );
});

Code Block

πŸš€ Key Takeaways:

  • State Management: Use useReducer for complex state changes in grids.
  • Memoization: Apply React.memo to cells to avoid re-renders unless necessary.
  • Performance Optimization: Leverage useCallback for memoizing functions and preventing redundant parent-child renders.

πŸ™Žβ€β™‚οΈRound 3: Hiring Manager Round

In this round, we focused on some output problems, team compatibility, past contributions, role expectations, and Cars24's tech direction.

➿Output Problems: Event Loop Question

❓Part 1: What will be the output for the following code?

let test = true
let counter = 0;

// setTimeout will change 'test' to false after 2 seconds
setTimeout(() => {
    test = false
}, 2000)

// setInterval runs every 200ms and logs counter until 'test' is false
setInterval(() => {
    if(test) {
        console.log(counter++)  // prints counter every 0.2 seconds
    }
}, 200)

Code Block

βœ… Answer:
It will print the counter every 0.2 seconds until 2 seconds pass. After that, test becomes false, stopping the interval.


❓Part 2: What will be the output for the following code if we replace setInterval with while-loop?

let test = true
let counter = 0;

// setTimeout will change 'test' to false after 2 seconds
setTimeout(() => {
    test = false
}, 2000)

// while loop runs until 'test' is false (but will block the main thread)
while(test) {
  console.log(counter++)  // prints counter infinitely
}

Code Block

βœ… Answer:
The counter will be printed infinite times because the while loop never exits. Since the while loop blocks the main thread, the setTimeout (which relies on the event loop) never runs, and the program is stuck in an infinite loop. This demonstrates JavaScript's single-threaded natureβ€”blocking the main thread means asynchronous code like setTimeout cannot execute.


❓Part 3: What's the exact issue in Part 1? What should be done to make sure it prints the counter every 0.2 seconds until 2 seconds and exits the function?

let counter = 0;

// Create an interval to print the counter every 200ms
let timerId = setInterval(() => {
    console.log(counter++)  // prints counter every 0.2 seconds
}, 200)

// After 2 seconds, clear the interval to stop printing the counter
setTimeout(() => {
    clearInterval(timerId)  // stops the interval after 2 seconds
}, 2000)

Code Block

βœ… Answer:
The issue in Part 1 is that the interval was never cleared, causing it to run indefinitely. The solution is to use clearInterval to stop the interval after 2 seconds. The setTimeout function calls clearInterval(timerId) after 2 seconds, ensuring the counter stops at the correct time. βœ…


🀝 Team Compatibility

We discussed how I collaborate with cross-functional teams and handle conflicts. I shared examples of working with PMs, designers, and backend engineers, emphasizing open communication and a solution-focused approach.

βš™οΈ Tech Direction

We talked about Cars24’s tech challenges, including site performance and scaling. I shared my experience with React, micro frontends, and SSR, expressing excitement about contributing to Cars24’s cutting-edge tech stack.

πŸ’Ό Past Product Contributions

I highlighted key products I’ve worked on, discussing my role in frontend development, improving performance, and user experience. I shared measurable results, like increasing load speeds and user engagement.

🎯 Role Expectations

We went over the responsibilities for the Frontend Engineer role at Cars24, including scalability and performance optimization. I aligned these with my long-term goals of leading frontend initiatives and building world-class user experiences.

Conclusion

It was a great conversation about aligning my skills and career goals with Cars24’s tech vision. I’m excited about the opportunity to contribute!


🧰 Round 4 – HR + Culture Fitment Discussion

In this round, the HR discussion focused on the following key aspects:

  • Complex Project Discussion:
    I detailed a complex project I had worked on, explaining the challenges I encountered and how I overcame them πŸ’‘.
  • Motivation for Role Switch:
    I shared why I was looking to switch roles and what I hoped to achieve at Cars24 πŸš—. I emphasized the importance of growth and new challenges in my career.
  • Company Culture & Career Trajectory:
    We discussed the company culture at Cars24 and the potential for career growth within the organization πŸ“ˆ. This gave me insights into how I could develop professionally and contribute to Cars24’s goals.
  • Contributions to the Frontend Team:
    I expressed how I could grow with the frontend team, focusing on contributing to their design system and performance optimization initiatives πŸ”§πŸ’». I also explained how I could play a key role in enhancing the user experience.

Hey there from LearnYard! πŸ‘‹

Glad to see you exploring the free content from our course! We’ve shared 10 valuable articles at no cost to help you get a real feel of what’s inside.

If you’ve found these helpful, we’d love to know! πŸ’¬
Share your thoughts or key takeaways on LinkedIn, Twitter, or Instagram β€” and don’t forget to tag Gourav Hammad & Mohammad Fraz. We’ll personally respond to your post!

Thanks for being part of the LearnYard journey. Keep learning, keep growing! πŸš€


Loved the free content? Want access to the full course β€” for free? πŸ’Έ

Here’s how: share the course with your friends using your affiliate link (you’ll find it on your profile or home page), and earn 20% commission on each sale.

Just 4–5 sales and you’ll recover the full course price of β‚Ή999/- πŸ”
So why wait? Start sharing, start earning, and unlock the rest of the course effortlessly! πŸ› οΈπŸ“ˆ


πŸ“š Keywords for SEO

  • Cars24 Frontend Interview Experience
  • Cars24 SDE-3 Interview
  • Cars24 ReactJS Round
  • JavaScript Deep Dive Cars24
  • Cars24 Machine Coding Round
  • Frontend Interview at Cars24
  • Cars24 Bangalore Interview Experience SDE-3 UI
  • Polyfill Questions Frontend Interview
  • Frontend Interview at Cars24

πŸ“Œ Final Verdict

πŸ“¨ Offer Received: Yes (within 4 business days after HR round)
❌ Did Not Join: Opted for a better offer from another organization.


πŸ“’ Hashtags for Visibility

#JavaScriptInterview #FrontendDeveloper #Cars24Careers #LearnYard #WebDevelopment #FrontendInterviewExperience #DSAwithJavaScript #MachineCodingRound #InterviewTips #SoftwareEngineerLife #TechHiring #CodeNewbie #FrontendMasters #JSInterviewPrep #MachineCodingRound #Cars24 #Cars24Interview #Cars24UI #Cars24Frontend