JavaScript Interview Questions

Master your next JavaScript interview with our comprehensive collection of questions and expert-crafted answers. Get prepared with real scenarios that top companies ask.

Find mentors at
Airbnb
Amazon
Meta
Microsoft
Spotify
Uber

Master JavaScript interviews with expert guidance

Prepare for your JavaScript interview with proven strategies, practice questions, and personalized feedback from industry experts who've been in your shoes.

Thousands of mentors available

Flexible program structures

Free trial

Personal chats

1-on-1 calls

97% satisfaction rate

Reading the answer isn't the same as saying it.

Book a mock interview

Study Mode

Choose your preferred way to study these interview questions

1. Can you explain the concept of hoisting in JavaScript?

Hoisting in JavaScript is a behavior in which variable and function declarations are moved to the top of their containing scope during the compile phase, before the code has been executed. It's important to note that only the declarations are hoisted, not initializations. So if you declare and initialize a variable or function at the end of your scope, while you can refer to it earlier in your code without getting a reference error, it will return 'undefined' because the initialization only happens at the point in the code where you wrote it.

Consider an example. If you try to use a variable before declaring it like this:

javascript console.log(myVar); // undefined var myVar = 5; console.log(myVar); // 5

Even though we used 'myVar' before declaring and initializing it, we didn't get a reference error. It returned 'undefined' because while the declaration ('var myVar') was hoisted, the initialization ('myVar = 5') wasn't. That's why when we logged it after initializing, it returned the correct value. In the case of function declarations, both the name and body are hoisted, so you can call a function before its declaration in the code.

2. What does 'this' keyword mean in JavaScript?

In JavaScript, 'this' is a special keyword that refers to the context in which a function is called, also known as the execution context. It doesn’t have a value until the function is called. The value it takes on depends on how the function is invoked, not where the function is defined.

For instance, when used inside a method of an object, 'this' refers to the object itself.

Consider an example with an object as follows:

javascript let car = { make: "Tesla", showMake : function(){ console.log(this.make); } } car.showMake(); // Tesla

In the code above, 'this.make' within the 'showMake' method refers to the 'make' property of the 'car' object because the function is being invoked as a method of the 'car' object.

But, if a function isn't called as a method, like a standalone function or a callback, 'this' doesn't refer to the object in which it's defined, it refers to the global object or is undefined, if in strict mode.

3. What are the different data types in JavaScript?

JavaScript includes both primitive and complex data types. The primitive data types include Number, String, Boolean, Undefined, Null, BigInt, and Symbol.

Number covers integers, floats, negative values, and NaN (Not a Number). String is a sequence of Unicode characters surrounded by single or double quotes. A Boolean can have only two values: true or false. Undefined means a declared variable but hasn’t been given a value. Null is an assignment value meaning no value or no object.

BigInt, a relatively new data type, can handle numbers larger than 253-1, which is the limit for the Number type. Symbol, also a newer addition, is a unique and immutable primitive value and can be used as a key for object properties.

On the complex side, we have Object, which can contain any of the primitive data types, as well as Arrays and Functions. Arrays are a type of object used to store multiple values in a single variable. Functions are probably the most important type in JavaScript, allowing you to encapsulate behavior, and they are themselves a type of object in JavaScript.

No strings attached, free trial, fully vetted.

Try your first call for free with every mentor you're meeting. Cancel anytime, no questions asked.

Nightfall illustration

4. Can you describe how to use JavaScript to interact with the Document Object Model (DOM)?

Sure. The Document Object Model (DOM) is an interface that represents how HTML and XML documents are read by the browser. It forms a tree-like structure, with the 'document' as the root object and HTML tags as branches. JavaScript is used widely to interact with the DOM to dynamically change content, structure, or style of a webpage.

You can select elements in the DOM using various methods, such as 'getElementById', 'getElementsByClassName', 'getElementsByTagName', or the more modern 'querySelector' and 'querySelectorAll' that take CSS-style selectors as their arguments.

Once you've selected elements, you can manipulate their attributes and properties (like the 'className' or 'innerHTML'), create new elements and add them to the DOM (using 'createElement' and 'appendChild'), change CSS styles (using the 'style' property), etc.

For instance:

javascript let heading = document.getElementById('myHeading'); heading.innerHTML = 'New Heading Text'; // changes the text of the element with ID 'myHeading'

You can also handle user interactions by adding event listeners to elements. An event listener waits for a specific event (like a click, hover, key press, etc.) to happen and then runs a function when that event is detected:

javascript let myButton = document.querySelector('button'); myButton.addEventListener('click', function () { // code to run when the button is clicked });

All these interaction capabilities make JavaScript essential for creating dynamic, interactive web pages.

5. Can you provide an explanation and example of a closure in JavaScript?

Closures in JavaScript is a concept where an inner function has access to the outer (enclosing) function's variables—scope chain. This scope chain consists of its own scope (variables defined between its curly brackets), the outer function's variables, and the global variables.

To put it in simpler terms, a closure gives you access to an outer function's scope from an inner function. In JavaScript, closures are created every time a function is created, at function creation time.

Here is an example of closure:

```javascript function outerFunction(outerVariable) { return function innerFunction(innerVariable) { console.log('outerVariable:', outerVariable); console.log('innerVariable:', innerVariable); } }

const newFunction = outerFunction('outside'); newFunction('inside'); ```

In the code above, innerFunction has access to outerVariable even after outerFunction has finished its execution, demonstrating closure. When we run newFunction('inside'), it logs both 'outside' and 'inside' because innerFunction has access to the outerVariable (due to its closure) and it has its own innerVariable.

6. Can you define what a JavaScript promise is and how to use one?

A Promise in JavaScript is an object representing the eventual completion or failure of an asynchronous operation. Essentially, it's a returned object to which you attach callbacks, instead of passing callbacks into a function.

Promises have three states: 1. Pending: The Promise's outcome hasn't yet been determined. 2. Fulfilled: The operation completed successfully. 3. Rejected: The operation failed.

You create a Promise with the 'new Promise' constructor which accepts a single argument—a callback with two parameters, typically named resolve and reject. The 'resolve' function is used to resolve the promise and can take a value which will be passed to the '.then' method. The 'reject' function is used when the promise cannot be fulfilled.

Example: javascript let promise = new Promise((resolve, reject) => { let taskDone = true; if(taskDone) { resolve('Task completed'); } else { reject(Error('Task not completed')); } }); You can use '.then' to schedule code to run after a promise fulfills, or if you need to catch an error, you can use '.catch' to handle the rejection.

javascript promise.then( (successMessage) => { console.log(successMessage); //logs 'Task completed' }, (err) => { console.log(err); //logs 'Task not completed' }); It's important to handle errors in promises to prevent them from failing silently which makes debugging difficult.

Out-loud check

Could you say this out loud, with a follow-up coming?

Drill it with a JavaScript mentor

7. Can you explain JavaScript’s map function and how it is used?

The map() function is a method built into JavaScript arrays that creates a new array with the results of calling a provided function on every element in the original array. It doesn't modify the original array, instead it returns a new array.

Here's a simple example. Suppose you have an array of numbers and you want to create a new array with each number squared:

javascript let numbers = [1, 2, 3, 4, 5]; let squared = numbers.map(function(num) { return num * num; }); console.log(squared); // [1, 4, 9, 16, 25]

In the code snippet above, numbers.map calls the provided function on each number in the array and stores the return value into the new 'squared' array.

The map function is especially useful when you want to transform elements in an array. The provided function could do anything from mathematical operations to reformatting strings. It's a clean, functional way to modify all elements in an array without resorting to loops or modifying the original array.

8. What is an arrow function in JavaScript, and how does it differ from a typical function?

An arrow function is a newer addition to JavaScript and provides a more concise syntax for writing function expressions. It is defined using the arrow '=>' notation.

An example of an arrow function looks like this:

javascript const square = num => num * num; // This function squares a number

In the code above, 'num' is the parameter and 'num * num' is the returned value. If you have multiple parameters, you need to wrap them in parentheses. If there are no parameters, you can use empty parentheses ().

Regular functions and arrow functions differ in two main ways. First, the syntax, as seen in the above, arrow functions are much more succinct. Second, and probably more importantly, they handle 'this' differently. Regular functions get their own 'this' value when you call them, usually pointing towards the object that calls them. But arrow functions do not have their own 'this' context, they inherit 'this' from the scope they're written in. This makes them more predictable, and means you don’t need to worry about binding 'this'.

```javascript let dog = { name: "Rex", activities: ["walk", "play"], showActivities() { this.activities.forEach((activity) => { console.log(this.name + " likes to " + activity); }); }, };

dog.showActivities(); // Rex likes to walk, Rex likes to play ``` In the code above, because we're using an arrow function in the forEach method, 'this.name' inside the forEach still refers to the 'name' property of the 'dog' object. If we were using a regular function, this would not be the case, because the function would have its own 'this' context.

User Check

Find your perfect mentor match

Get personalized mentor recommendations based on your goals and experience level

Start matching

9. Can you describe the principles of object-oriented programming (OOP) in JavaScript?

In JavaScript, Object-Oriented Programming (OOP) is a coding style that uses objects and classes to structure and organize code. Here, the data is structured around objects, which can contain related properties and methods.

Let's go through four key principles of OOP in JavaScript:

  1. Encapsulation: This means grouping related variables and functions (properties and methods) together in an object, so they are encapsulated. This makes it easier to understand how a piece of code works because its behavior is defined by its own methods and properties.

  2. Inheritance: This principle allows a class to inherit properties and methods from another class. In JavaScript, one class (the "child" or subclass) can extend another class (the "parent" or superclass), inheriting all its features.

  3. Polymorphism: This means the ability to call the same method on different objects and have each of them respond in their own way. This is commonly implemented in JavaScript using prototype-based inheritance.

  4. Abstraction: This principle is about reducing complexity by hiding unnecessary details and showing only essential features to users. In JavaScript, this can be achieved by using private properties and methods that are only accessible inside an object.

These OOP principles allow for more modular and reusable code. In JavaScript, before ES6, OOP was implemented using constructor functions and prototype chains, but ES6 introduced classes which makes it more similar to OOP in other languages.

10. What does it mean if a language is described as 'single-threaded', like JavaScript?

When a language is described as 'single-threaded', like JavaScript, it means that only one operation can be in progress at a time in its execution context. JavaScript has a single call stack where it keeps track of what function is currently being run and its caller functions. It processes one command at a time from the top of the stack.

But it's important to clarify that JavaScript's runtime environment—typically browser or Node.js—might not be single-threaded. They often provide APIs to allow for certain tasks (like HTTP requests or reading/writing files) to be handled in the background on separate threads, through asynchronous operations. That's how JavaScript, which is single-threaded, can still handle many tasks seeming simultaneously.

It's this combination of JavaScript's single-threaded nature with the ability to do non-blocking asynchronous operations that makes JavaScript particularly well-suited for tasks like handling user interactions on a webpage or dealing with multiple requests on a server.

11. What is a JavaScript ‘IIFE’ (Immediately Invoked Function Expression) and why might you use it?

An Immediately Invoked Function Expression (IIFE) is a JavaScript function that runs as soon as it is defined. The syntax looks like this:

javascript (function () { // statements })();

The function expression is wrapped in parentheses () to tell the interpreter to treat it as an expression, not a declaration. And then the trailing parentheses () cause the function to be immediately executed or invoked.

IIFEs are often used to create a new scope, thus avoiding variable hoisting from within blocks. They allow you to define variables that don't pollute the global scope.

For example, in the code below:

```javascript (function () { var localVariable = "I'm local"; console.log(localVariable); // I'm local })();

console.log(localVariable); // undefined ```

Here, the localVariable is not accessible outside the scope of the IIFE, allowing for better control over variable lifetimes and preventing global scope pollution. This is very beneficial in large codebases where you might accidentally overwrite global variables with the same name.

12. How do you debug JavaScript code?

There are several ways to debug JavaScript code.

  1. console.log(): The easiest and simplest method for debugging is using the console.log() method to print out values to the console. It allows you to examine what's happening in your code line-by-line and see what values variables are holding at certain points.

  2. Developer Tools: Modern browsers come with built-in developer tools that include a JavaScript debugger. With this debugger, you can set breakpoints in your code which let the execution stop at a certain point. This allows you to step through your code one line at a time and observe the values of variables at each step. You can also see if any exceptions are being thrown.

  3. Using a Linter: A linter like ESLint can catch many common errors like undeclared variables or mismatched brackets before runtime.

  4. Unit Testing: Writing unit tests can help you catch errors and unexpected behavior in your functions. You can write tests to see if your functions return what you expect them to when given certain inputs. Any reliable testing library like Jest, Mocha, or Jasmine can help here.

  5. Debugging Keyword: JavaScript also has a keyword debugger. When the developer console is open, this statement causes a breakpoint to be set and allows you to inspect the current state.

Remember that debugging is a skill that improves over time. The more you practice and familiarize yourself with the tools available, the better you'll get at diagnosing and fixing issues in your code.

Out-loud check

Could you say this out loud, with a follow-up coming?

Drill it with a JavaScript mentor

13. What are some differences between null and undefined in JavaScript?

In JavaScript, undefined and null are both special values that represent the absence of a value. While they may seem similar, they have different uses and meanings.

Undefined means a variable has been declared but has not yet been assigned a value. For instance, if you declare a variable let myVar; and log it, you'll get undefined because none value has been assigned to myVar.

On the other hand, null is an assignment value. It means no value or no object. It needs to be assigned to a variable to indicate that the variable has no value. To put it another way, null represents the intentional absence of any object value.

In terms of comparison, 'undefined' is equal to 'null' with abstract equality (undefined == null will yield true). However, with strict equality (undefined === null), they are not equal because they are of different types.

So essentially, undefined typically means a variable is declared but not assigned, while null means a variable is intentionally assigned a null value indicating the absence of value.

14. How could JavaScript code interact with CSS to dynamically change the style of an element on a webpage?

JavaScript can interact directly with the style of webpage elements using the 'style' property. You can first select the element you want to manipulate using different JavaScript methods such as getElementById, getElementsByClassName, getElementsByTagName, or more modern querySelector and querySelectorAll and then edit its CSS properties with the style property.

Here's an example where we change the color of a text in a paragraph with the id "myText":

javascript let paragraph = document.getElementById('myText'); paragraph.style.color = 'red';

In this instance, we're changing the text color to red. The 'style' property here represents the style attribute of the 'myText' element. Each CSS property is available under style as a property and we can assign new values to them.

Keep in mind, however, that directly manipulating an element’s style is generally advised against because it makes styles harder to manage by spreading them over HTML, CSS and JavaScript files. It's often better to define CSS classes and then add or remove these classes using JavaScript.

For example:

javascript let paragraph = document.getElementById('myText'); paragraph.classList.add('active');

In this example, we're adding the 'active' class to the 'myText' element, which could have a number of styles defined in the CSS.

15. How is event bubbling handled in JavaScript, and when might you use it?

Event bubbling is a term you'd come across when dealing with JavaScript event propagation. When an event, like a click, is fired on an element that is nested inside other elements, the event doesn't completely end at just that target element. The event starts from the target element and "bubbles up" through the parent elements in the DOM tree till it reaches the root.

Here's an example. Let's say you have a button inside a form. Both elements have click events. When you click the button, the event is triggered on the button first and then bubbles up through the DOM until it reaches the form, and the form's event is then triggered.

This can actually be very useful when you want similar event listeners for multiple elements. Instead of adding event listeners to each individual child, you can add an event listener to their common parent due to event bubbling.

Event bubbling can be stopped using the event.stopPropagation() method. It prevents further propagation of the current event in the capturing and bubbling phases. So, if you don't want the click event to fire on the form when you click the button, you could call event.stopPropagation() in the button's click event handler.

Be cautious when using stopPropagation though, as it can sometimes have unintended side effects by preventing other events from firing when they should.

16. What is JSON and how does JavaScript interact with it?

JSON, or JavaScript Object Notation, is a lightweight data interchange format that is easy for humans to read and write and easy for machines to parse and generate. It is often used when data is sent from a server to a web page.

JSON is a text format that is completely language independent but uses conventions that are familiar to programmers of the C-family of languages, including C, C++, C#, Java, JavaScript, Perl, Python, and many others.

In JavaScript, JSON is a global object used for parsing and stringifying data. The JSON.parse() method is used to convert a JSON string into a JavaScript object, and JSON.stringify() turns a JavaScript object into a JSON string.

Here’s an example:

javascript let jsonString = '{"name":"John", "age":30, "city":"New York"}'; let jsObject = JSON.parse(jsonString); console.log(jsObject.name); //John

In the example above, we have a string of JSON data which we then parse into a JavaScript object that we can interact with.

You can convert JavaScript objects to JSON to send to a server, or receive JSON from a server and convert it to JavaScript. This makes JSON a very important part of interacting with many types of web APIs.

17. Can you explain asynchronous programming in JavaScript?

Asynchronous programming in JavaScript is a way of handling operations that may take a long time to complete, such as requests to a server, reading files, or querying a database. It allows operations like these to happen in the "background" while the rest of your code continues to execute, preventing your application from appearing frozen or unresponsive.

JavaScript uses callbacks, promises, and async/await to deal with asynchronous operations.

A callback is a function that is passed as an argument to another function and is executed once the long-running operation completes.

Promises are an enhancement over callbacks, providing a more readable, clean syntax and better error handling. A Promise in JavaScript represents the eventual completion or failure of an asynchronous operation.

Async/await introduced with ES2017 makes working with Promises even easier. It makes asynchronous code look and behave like synchronous code. The async keyword is used to define an async function. Inside an async function, you can use the await keyword before any Promise to pause execution of the function until the Promise resolves or rejects.

It's all about writing non-blocking code, meaning your program doesn't have to stop and wait for time-consuming tasks to finish before moving on. It's a key part of JavaScript's nature, especially its use in Node.js and frontend web development.

18. What are the differences between the '==' and '===' operators in JavaScript?

In JavaScript, '==' and '===' are both comparison operators but they differ in how they compare values.

'==' is known as the abstract equality comparison operator. It checks for equality of values but not equality of type. Before comparison, it performs type coercion if the types of the two values are different, which can lead to some unexpected results when comparing certain values.

javascript 0 == false // true, because false is equivalent to 0 in the numeric type '2' == 2 // true, because '2' is coerced to a number before comparison null == undefined // true, these are the only two values which are equal to each other

'===' is known as the strict equality comparison operator. It checks for equality of value as well as type. It does not perform type coercion and so it ensures the values are equal and of the same type.

javascript 0 === false // false, because they are of a different type '2' === 2 // false, again different type null === undefined // false, not the same value/type

In most cases, it's recommended to use '===' over '==' because it avoids potential confusion arising from the automatic type conversion done by '=='.

Out-loud check

Could you say this out loud, with a follow-up coming?

Drill it with a JavaScript mentor

19. Can you explain arrays in JavaScript and how they are different from arrays in other languages?

Arrays in JavaScript are a type of object that are used to store multiple values in a single variable. Each value (or element) in an array has a zero-based index. You can use these indexes to access and manipulate the array elements.

Here is an example of an array in JavaScript:

javascript let fruits = ['apple', 'banana', 'orange']; console.log(fruits[0]); // "apple" fruits[1] = 'grape'; console.log(fruits); // ["apple", "grape", "orange"]

In the code above, 'fruits' is an array that stores three strings. You can access the elements using their indexes or modify them by assigning a new value to a specific index.

Arrays in JavaScript are different than arrays in many other languages. In JavaScript, arrays are dynamic, meaning they can grow or shrink in size dynamically. You can easily push elements into an array or remove them, which automatically adjusts the size of the array.

Also, JavaScript arrays can hold different types of data in one array. So you can have numbers, strings, objects, and even other arrays all in the same array. Example: let myArray = [3, 'hello', {name: 'Bob'}, [1, 2, 3]];

This is not the case in many other languages, where arrays are of a fixed size and can typically only hold one type of data.

20. What tools or frameworks do you use to test your JavaScript code?

For testing JavaScript code, there are several tools and frameworks that are both powerful and popular in the community.

For unit testing, "Jest" is a widely used tool. Developed by Facebook, Jest is a powerful testing framework that can run tests in parallel for efficient performance. It includes a complete set of features such as mock functions, code coverage reports, and asynchronous testing.

For end-to-end testing, "Cypress" is a popular choice. It comes with a nice GUI for visually running through tests in the browser, automatically waits for commands and assertions before moving on, and it's capable of simulating user behavior in the browser, such as typing or clicking.

Aside from these, for testing user interfaces especially when working with React, "React Testing Library" is considered a great tool. It encourages writing tests that closely resemble how users would interact with your app, making the tests more maintainable, understandable, and robust.

'Enzyme', developed by Airbnb, is another popular tool for testing React components, and it works well with Jest.

Finally, "Mocha" and "Chai" are also popular for unit testing, providing test runners and assertion libraries respectively. They are typically used together and are known for their flexibility and modularity.

All these tools have different strengths, and the best one to use depends on the specific needs and context of your project.

21. Can you explain temporal dead zone in JavaScript?

The Temporal Dead Zone (TDZ) in JavaScript is a behavior associated with let, const and class declarations. It's the period between entering a scope where a variable is declared and the actual declaration and initialization of that variable.

In other words, even though the variable's scope is entered, it isn’t available until it is actually declared with let or const. If you try to access it within this period, JavaScript will throw an error.

The TDZ starts at the beginning of the containing scope and ends at the declaration and initialization of the variable. Here is a simple example to illustrate:

javascript console.log(myVar); // Throws ReferenceError: myVar is not defined let myVar = 10;

In the code above, even though myVar is in scope, we're trying to log it before it's declared and initialized. As a result, we get a ReferenceError due to the TDZ.

The concept of the TDZ is an important part of understanding how JavaScript works. It helps prevent errors by making sure variables are not used before they're initialized, which is behavior that could be confusing or introduce subtle bugs.

22. How to avoid callback hell in JavaScript?

"Callback Hell" in JavaScript refers to the scenario when too many nested callback functions are used, generally resulting from too many asynchronous operations being performed one after the other. It makes your code hard to read and understand, and it's also difficult to handle errors. Here are some strategies to avoid it:

  1. Modularization: Break your code down into smaller, more manageable functions. Instead of nesting callbacks, you can define functions that handle each step of your asynchronous operations and then chain them together.

  2. Promises: Promises are objects representing a future completion (or failure) of an asynchronous operation and its result. They can be used to write cleaner asynchronous code, as they can be chained together and will catch any errors thrown in the chain.

  3. Async/Await: Introduced in ES8, async/await is a syntactic sugar over promises that allows you to write asynchronous code as if it were synchronous. An async function returns a promise, and the await keyword can be used inside an async function to pause and wait for the promise's resolution or rejection. It really cleans up asynchronous JavaScript code, making it easier to understand and maintain.

Here's an example of async/await:

```javascript async function asyncAction() { try { const result = await someAsyncOperation(); console.log(result); } catch (error) { console.log('An error occurred: ', error); } }

asyncAction(); ```

This code does the same thing as a corresponding callback-based code, but without the nested callbacks and with better readability and error handling.

23. What are JavaScript callbacks and how to use them?

A callback in JavaScript is a function that is passed as an argument to another function and is executed after some operation has been completed. Because JavaScript is single-threaded, callbacks are commonly used to handle asynchronous operations so that the later operation doesn't need to block and wait for the earlier one to complete.

For example, suppose you have a function that takes some time to complete, like fetching data from a server. You want to perform another operation as soon as the data comes back, but you don't want to pause the rest of your code while waiting for the data. Here's where we use callbacks.

Here is an example of using a callback function with the built-in JavaScript function setTimeout:

```javascript function greet() { console.log("Hello, World!"); }

setTimeout(greet, 3000); `` In the code above,greetis the callback function.setTimeout` takes two arguments: the callback function and the number of milliseconds to wait before executing the callback function. After 3 seconds (3000 milliseconds), "Hello, World!" will be logged to the console.

While callbacks are a fundamental part of JavaScript and crucial for asynchronous programming, using a lot of callback functions can lead to deeply nested code, often referred to as 'callback hell.' This has been mitigated in modern JavaScript with the introduction of Promises and async/await syntax.

24. How can you ensure that your JavaScript code is clear and readable?

Ensuring that your JavaScript code is clear and readable is all about good coding practices and conventions. Here are some tips:

  1. Consistent Naming Conventions: Choose conventions for naming your variables, functions, classes etc., (such as camelCase for variables and PascalCase for classes) and stick to them consistently. Also, name them meaningfully. For example, a variable to hold a user's age could be userAge, not just age or a.

  2. Commenting: Use comments to explain the purpose of complex portions of your code. However, good code should be self-explanatory most of the time, if you're finding yourself writing long comments to explain what's going on, it might be a sign that your code could be refactored to be more straightforward.

  3. Use Indentation and Code Formatting: Indent your code consistently to clearly show the program's structure. Many text editors have auto-formatters that can help with this.

  4. Keep Functions Small and Single-Purpose: Functions should do one thing and do it well. If a function is responsible for more than one thing, it can often be split into multiple smaller functions.

  5. Modularize your Code: Break your code up into smaller, reusable pieces (modules). This not only makes code easier to read and understand but also makes it easier to debug and test.

Finally, consider using tools like JSLint or ESLint. These tools can enforce consistent styling, catch potential bugs, and encourage best practices. Incorporating these tools into your development process can greatly increase the readability of your code, especially in larger projects or teams.

Out-loud check

Could you say this out loud, with a follow-up coming?

Drill it with a JavaScript mentor

25. How does the block scope work in JavaScript?

Block scope is a type of scope in JavaScript that is defined within curly braces {}. It's important to note that JavaScript didn't have block scope until the introduction of let and const keywords with ES6 (ES2015). The var keyword, which was traditionally used to declare variables in JS, is not block-scoped but function-scoped.

So when you declare a variable with let or const inside a block (like inside an if condition block, for loop, or simply a standalone block), it's only accessible within that block and any nested blocks.

Here's an example:

```javascript { let blockScopedVariable = "I'm block scoped"; console.log(blockScopedVariable); // "I'm block scoped" }

console.log(blockScopedVariable); // Uncaught ReferenceError: blockScopedVariable is not defined ```

In the example above, blockScopedVariable is only accessible within the block where it's defined. Attempts to access it outside of the block result in an error.

This is different from function-scoped var declarations, where a variable declared inside a block is still accessible outside that block if it's not defined within a function.

Block scope is helpful in controlling where exactly your variables can be accessed from and reducing the risk of accidental modification from other parts of your code. It should be the default level of scoping to use for your rampant variable declaration needs.

26. What are template literals in JavaScript?

Template literals are a feature in ES6 (ES2015) JavaScript that provides an easy way to create strings with embedded expressions or variables. This could make it easier to create complex strings, including strings that span multiple lines.

Template literals are defined using the backtick () character rather than the traditional single or double quotes. To embed any expression within the string, you wrap it in ${}. Here's an example:

javascript let name = "World"; let greeting = `Hello, ${name}!`; console.log(greeting); // "Hello, World!"

In this example, the variable name is embedded in the string using ${name}. The output is "Hello, World!".

You can put any JavaScript expression inside the placeholder, including function calls and arithmetic operations. Multi-line strings are also easily expressed in template literals without the need for an escape character or concatenation:

javascript let multiLineString = `This is a string that spans multiple lines`; console.log(multiLineString);

This will output the string exactly as it's formatted, preserving the line breaks.

Overall, template literals can make your JavaScript code cleaner and easier to understand, particularly when working with complex or dynamic strings.

27. What is the purpose of JavaScript modules?

JavaScript modules are a way to share code across multiple files. They help in organizing code into smaller self-contained blocks that have a specific functionality. It's all about maintaining clean, easily-manageable code in larger JavaScript programs.

In a module, you can create variables, functions or classes, and make them available to other JavaScript files by exporting them using the export statement. Then, other JavaScript files can use that functionality by importing it with the import statement.

For instance, you might have a module that handles all operations related to dates. That might include a function to format dates, calculate differences between dates, etc. In this case, using a module makes your code more maintainable and easier to reason about, because all related functions are grouped together in a module.

Here's a simple example:

javascript //module.js export function sayHello() { console.log("Hello!") }

javascript //main.js import { sayHello } from './module.js'; sayHello();

In the example above, sayHello function is defined in 'module.js' and exported. 'main.js' then imports sayHello function from 'module.js' and uses it.

Modules are a fundamental part of modern JavaScript and are used heavily in modern web development workflows with tools like Webpack and Babel. They also are native feature in JavaScript in ES6 and browser environments.

28. How can you handle exceptions in JavaScript?

Exceptions in JavaScript can be handled using try...catch statements. The try statement allows you to define a block of code to be tested for errors while it is being executed. If an error does occur, execution of try block is stopped, and control is passed to a catch block.

Here’s a simple example:

javascript try { undefinedVariable++; } catch (error) { console.log("An error occurred: " + error.message); }

In the code above, undefinedVariable is not defined. Therefore, when we try to increment it, JavaScript throws an error. We catch this error in our catch block and log an error message to the console.

It's also good practice to include a finally clause. The finally clause will contain code that runs whether or not an error was caught.

javascript try { undefinedVariable++; } catch (error) { console.log("An error occurred: " + error.message); } finally { console.log("Finally block executed"); }

Exception handling is important to gracefully manage errors and provide useful feedback to users or logs. It prevents your program from unexpectedly crashing and helps maintain a smooth user experience.

29. How does prototypal inheritance work in JavaScript?

Prototypal inheritance is the way JavaScript objects inherit features and properties from one another.

In JavaScript, objects are mutable, meaning they can be altered at any time. If you have an object 'a', you can add and modify properties and thus change what's available. This is what makes Prototypal Inheritance possible.

Every object in JavaScript has a private property called its [[Prototype]] which comes from the object's constructor and is essentially a reference to another object. When you try to access a property that's not available on an object, JavaScript will look up this property in the object's [[Prototype]].

If it doesn't find the property there, it continues the search up the prototypal chain until it either finds the property or until it reaches an object with a null [[Prototype]]. If it still doesn't find the property, it will return 'undefined'; this is how JavaScript implements prototypal inheritance.

Here's an example:

```javascript let vehicle = { hasWheels: true, };

let car = Object.create(vehicle);

console.log(car.hasWheels); // true ```

In the code above, car object is created as a prototype of vehicle. When we try to access the hasWheels property on car, it isn't found. So, JavaScript looks up on its [[Prototype]], finds hasWheels on vehicle, and logs true.

Prototypal inheritance allows JavaScript objects to be very memory efficient, as they can share properties and methods along the prototype chain. It's a unique and powerful aspect of JavaScript, but it needs to be managed carefully, as changes in one place can have unexpected results in another.

30. What is destructuring assignment in JavaScript and how do you use it?

Destructuring assignment is a feature introduced in ES6 that allows you to unpack values from arrays, or properties from objects, into distinct variables.

For an array, you can use it like this:

javascript let nums = [1, 2, 3]; let [one, two, three] = nums; console.log(one, two, three); // 1, 2, 3

In the code above, nums is an array. We create new variables one, two, and three and assign them the values from the nums array in order.

Destructuring assignment can also be used with objects:

javascript let person = {name: 'John', age: 30}; let {name, age} = person; console.log(name, age); // 'John', 30 In the code above, person is an object. We create new variables name and age and assign them the corresponding property values from the person object.

Destructuring assignment can make your code cleaner and easier to read by reducing the need for repetitive property references. It's especially handy when working with functions that return arrays or objects.

31. What is event loop in JavaScript?

The Event Loop is a key aspect of the JavaScript runtime system that takes care of executing code, collecting and processing events, and executing queued subtasks. It's the mechanism that allows JavaScript, which is single-threaded, to handle concurrent operations and asynchronous functions.

Here's a simplified explanation of how the event loop works:

  1. When the JavaScript engine runs your script, it first goes through the synchronization code—the standard top-to-bottom JavaScript that you've written in your script.

  2. Once it's finished with this synchronous code, it looks at the Callback Queue where any callbacks from your asynchronous code will be queued to run. This might be DOM events, network requests, timers, etc.

  3. If the callback queue is not empty, the Event Loop adds the callbacks to the Call Stack (which is where the JavaScript engine maintains the list of frames to execute), one by one, to be executed in order.

  4. This process continues on a loop—the Event Loop—where new callbacks are continuously checked for and processed.

The Event Loop is the reason why JavaScript can have non-blocking I/O, even though JavaScript is single-threaded. It's pivotal in understanding the working of promsies, callbacks, async/await, etc. in JavaScript.

32. How is React.JS different from Vanilla JavaScript?

Vanilla JavaScript refers to plain or pure JavaScript — without any additional libraries or frameworks.

React.js, on the other hand, is a JavaScript library developed by Facebook. It's used for building user interfaces, specifically for single-page applications where you need a fast, interactive user interface. It allows you to create reusable UI components, manage component state, and manage application state using hooks or more complex solutions like Redux.

React stands out for its virtual DOM implementation which optimizes rendering and improves performance, especially in large scale applications. It also enables "declarative" coding style for UI, allowing you to write code that describes what should be rendered, and React takes care of updating the UI to match the state.

So, when you're using React.js, you're still using JavaScript, but you're also utilizing the tools and structures provided by the React library to create more complex, interactive user interfaces with less code and better performance characteristics than you might get with vanilla JavaScript.

Another thing to note, while you can manipulate the DOM directly in Vanilla JavaScript, in React, you'll be warned against doing so and are encouraged to manipulate state instead, and let React update the DOM based on this state. This is key to React's performance optimizations.

33. What is the concept of functional programming in JavaScript?

Functional programming in JavaScript is a programming paradigm where programs are constructed by applying and composing functions. It relies heavily on immutability and pure functions, which return the same result given the same arguments and have no side-effects.

Here are some key concepts in functional programming in JavaScript:

  1. Pure Functions: As mentioned, these are functions that always return the same output given the same inputs, without altering any external state or producing side effects.

  2. First-Class and Higher-Order Functions: JavaScript supports first-class functions, meaning functions can be assigned to variables, passed as arguments into other functions, and returned from other functions. A higher-order function is a function that accepts other functions as arguments, returns a function, or both.

  3. Immutability: In functional programming, data is immutable, meaning it cannot be changed after it’s created. If you want to change some data, you create a new copy.

  4. Function Composition: Functions should be small and perform a single task. Function composition is the process of combining two or more functions in order to produce a new function or perform some computation.

  5. Map, Reduce, Filter: JavaScript provides several built-in methods inspired by functional programming such as map(), reduce(), and filter(), that can be used to transform, combine or filter arrays without mutating them.

Functional programming can lead to cleaner, more modular and maintainable code, though it also comes with a learning curve and isn't always the best approach for all problem types.

34. How would you explain the difference between 'let', 'const', and 'var' in JavaScript?

'var', 'let', and 'const' are all used to declare variables in JavaScript, but they differ in how and where the variables can be used or manipulated.

  1. 'var': This is the oldest way to declare variables in JavaScript. Variables declared with 'var' are function-scoped, which means they exist within the function where they are declared. If they're declared outside of any function, they're globally scoped. They also can be redeclared and updated.

  2. 'let': Introduced in ES6, 'let' variables are block-scoped, meaning they exist only within the block they're declared in. They can't be redeclared within the same scope but they can be updated (i.e., the value can be changed after declaration).

  3. 'const': Also introduced in ES6 and is block-scoped as well. However, once a 'const' variable has been assigned, it can neither be redeclared nor updated. This doesn't mean the variable is immutable—just that the identifier cannot be reassigned. For instance, if the const variable is an object, the properties of the object can still be modified.

One good programming practice in modern JavaScript is to use 'const' by default, and only use 'let' when you know the variable will need to be reassigned later. 'var' is generally avoided in modern JavaScript code due to its confusing function scope and hoisting behavior.

35. What is AJAX and how would you implement it in JavaScript?

AJAX stands for Asynchronous JavaScript and XML. It is not a language, but a technique for accessing web servers from a web page asynchronously. It allows you to update parts of a web page without doing a full page refresh. Despite its name, AJAX doesn't require the use of XML; we can use JSON and other formats for data exchange as well.

To implement AJAX in JavaScript, we primarily use the XMLHttpRequest object or the newer fetch API. Here's a basic example using the XMLHttpRequest object:

javascript let xhr = new XMLHttpRequest(); xhr.open('GET', 'https://api.example.com/data', true); xhr.onreadystatechange = function () { if (xhr.readyState == 4 && xhr.status == 200) { let response = JSON.parse(xhr.responseText); console.log(response); } }; xhr.send();

In the above example, we create a new XMLHttpRequest, open a connection to a URL (https://api.example.com/data in this case), specify a callback function that will be called when the state of the request changes (this is where we parse and handle the response), and then we send the request.

To do the same with fetch, we could write:

javascript fetch('https://api.example.com/data').then(response => response.json()).then(data => console.log(data)).catch(error => console.log('Error:', error));

fetch returns a promise that resolves to the Response object, which we can parse as JSON (or text, blob etc depending on the response type). The resulting data is then logged to the console.

Both methods achieve the same result but fetch provides a more powerful and flexible feature set. fetch is promise based and avoids callback hell, while XMLHttpRequest uses event listeners and can become quite messy if dealing with more complex requests.

36. What is the purpose of JavaScript classes?

JavaScript classes, introduced in ES6, are a syntactic sugar over JavaScript's existing prototype-based inheritance. The class syntax does not introduce a new object-oriented inheritance model to JavaScript, but provides a much simpler and clearer syntax to create objects and deal with inheritance.

Classes provide a way of defining "blueprints" for creating many objects of the same kind. Each object created from this "blueprint" will have the same properties and methods. Here's a basic example of a JavaScript class:

```javascript class Car { constructor(brand) { this.brand = brand; }

showBrand() { return this.brand; } }

let myCar = new Car("Toyota"); console.log(myCar.showBrand()); // Outputs: "Toyota" ```

In the example, Car is a class, and it has a constructor method that's called when we use the new keyword to create new objects of the class. showBrand is another method that all Car objects will have.

While JavaScript is fundamentally a prototype-based language and doesn't have classes in the traditional sense like languages like Java or C++, the class syntax provides a more familiar and easier to understand structure for developers coming from a class-based language, and for those who prefer a more structured approach to object-oriented programming.

37. How would you create a deeply nested JSON object from a given array in JavaScript?

Creating a deeply nested JSON object from an array can be accomplished in several ways in JavaScript, but one of the most straightforward is using the reduceRight function.

Here's an example using reduceRight:

```javascript let array = ['a', 'b', 'c', 'd']; let nestedObject = array.reduceRight((obj, item) => ({[item]: obj}), {});

console.log(nestedObject); ```

In this example, reduceRight iterates the array from right to left, with each array item becoming a key in a new object that includes the current value of obj as its value ({[item]: obj}).

On the first iteration, when the current item is 'd', the obj is {} (the initial value of obj). The resulting object from this iteration is { d: {} }. On the next iteration, when the item is 'c', obj is { d: {} }, so the resulting object is { c: { d: {} } }. This process continues until we've gone through the whole array, creating a deeply nested object.

The logged nestedObject would be {'a': {'b': {'c': {'d': {}}}}} in the above case. This is a simple way to nest objects inside each other based on an array, creating a hierarchy from the array items.

38. Can you describe the difference between the global scope and the local scope in JavaScript?

In JavaScript, the scope refers to the accessibility or visibility of variables, functions, and objects in some particular part of your code during runtime. In other words, it defines the portion of the code where a variable or a function can be accessed from.

There are mainly two types of scope in JavaScript - global scope and local scope.

A variable declared outside a function becomes a global variable and it is accessible from any part of the code, even inside functions. Like so:

```javascript var globalVar = "I'm global!";

function someFunction() { console.log(globalVar); }

someFunction(); // Outputs: "I'm global!" ```

In the code snippet above, globalVar is declared outside the function and is accessible anywhere in the code, including inside someFunction.

On the other hand, if a variable is declared inside a function, it has a local scope and can only be accessed within that function:

```javascript function anotherFunction() { var localVar = "I'm local!" ; console.log(localVar); }

anotherFunction(); // Outputs: "I'm local!" console.log(localVar); // ReferenceError: localVar is not defined ```

In the second code snippet, localVar is declared inside anotherFunction and can only be accessed within that function. Any attempt to access localVar outside of its function results in a ReferenceError.

It's important to use these scopes appropriately to avoid unexpected behaviors and bugs in your JavaScript code. Avoid using the global scope where possible to avoid naming clashes and keep your code modular and predictable. Local scope, especially function scope and block scope (with let and const), is recommended.

39. What is the use of 'Strict Mode' in JavaScript?

'Strict Mode' in JavaScript is a feature introduced in ES5 that allows you to place your JavaScript in a 'strict' operating context. This strict context prevents certain actions from being taken and throws more exceptions. The literal expression "use strict"; instructs the browser to use JavaScript in strict mode.

You enable strict mode by adding 'use strict'; at the beginning of a file, a program, or a function. This helps catch common coding mistakes and unsafe actions such as:

  • Assigning a value to a read-only global variable or function (like undefined, NaN, Infinity)
  • Creating a variable without declaring it first
  • Deleting variables, functions, or function arguments
  • Duplicating parameter names in function definitions

Here's an example where strict mode will make a difference:

javascript "use strict"; x = 3.14; // This will cause an error because x is not declared

Stricter mode helps you to write cleaner, more reliable, and more maintainable code. It's recommended to turn on strict mode in most situations to avoid the possibility of silent errors. Essentially, it ensures that you are writing a safer, more robust code that adheres to better coding standards.

40. Can you talk about how to use promises and async/await together in JavaScript?

Sure. Promises are the foundation for async/await syntax in JavaScript, so they naturally work together.

A Promise is an object representing a future completion (or failure) of an asynchronous operation and its resulting value. It has three states: pending, fulfilled, and rejected.

The async/await syntax is built on top of promises. It's like syntactic sugar that makes asynchronous code look and behave a bit more like synchronous code, which can make it easier to understand and write.

An async function always returns a promise. The await operator is used inside an async function to pause execution of the function and wait for a Promise's resolution or rejection. Here's how you might use them together:

```javascript async function fetchData(url) { try { const response = await fetch(url); const data = await response.json(); console.log(data); } catch (error) { console.error('Error:', error); } }

fetchData('https://api.example.com/data'); ```

In the code above, fetchData is an async function, and it uses await to pause and wait for two promises: one from the fetch call itself, and one from the .json() call that reads the response body. If any of these promises reject, the error will be caught and logged.

By using async/await, we're able to handle promises in a way that's easier to read and reason about, without lots of nested callbacks. It provides a much cleaner and more intuitive way to write asynchronous code that relies on promises.

You've got the answers. Now rehearse them.

Studying questions tells you what might come up. A mock interview tells you how you hold up when it does, follow-up questions and all. Find the weak spots now, with a JavaScript mentor who has sat on the other side of the table.

Get Interview Coaching from JavaScript Experts

Knowing the questions is just the start. Work with experienced professionals who can help you perfect your answers, improve your presentation, and boost your confidence.

Complete your JavaScript interview preparation

Comprehensive support to help you succeed at every stage of your interview journey

Table of Contents

What a JavaScript interview actually tests in 2026

A JavaScript interview in 2026 tests whether you can reason about the language out loud, not just recite definitions. Interviewers now weight ES2025 syntax and scenario debugging alongside the closures and the event loop that have always shown up, so a question bank built only on classic fundamentals leaves a real gap.

That gap matters because the bar rises with the language. The questions above cover the fundamentals well, but the modern syntax cluster and the "what does this code print" format are where candidates who studied a static list tend to freeze. Knowing the answer on paper is not the same as producing it when a stranger is grading you.

The sections below add what a card deck cannot. You get a difficulty-tier map for the 40 questions, the ES2025 questions most lists still miss, the scenario format interviewers favor, a four-week prep approach, and the evidence on why rehearsing your answers out loud closes the part of the gap reading never will.

TL;DR

  • Prepare across all three difficulty tiers, from junior fundamentals to senior system reasoning.
  • Brush up on ES2025 syntax - optional chaining, nullish coalescing, Set algebra, and immutable array methods - which many older lists skip.
  • Practice scenario questions like "why does this loop log 3, 3, 3" out loud, because interviewers use them to test reasoning, not recall.
  • JavaScript is the most-used language at 66% and has ranked number one every year since 2011 (Stack Overflow, 2025), so the bar stays high.
  • Rehearse your answers with a mentor who has passed the interview, since reading a model answer differs from delivering one live.

How JavaScript interviews are structured by difficulty level

JavaScript interviews are organized by difficulty level, scaling from junior fundamentals through mid-level patterns to senior system reasoning. Almost every prep resource groups questions this way, and the map below shows where the 40 questions above sit so you can read the deck as a progression rather than a flat pile. Knowing your tier tells you which questions to drill first.

Junior rounds probe core mechanics: variables, scope, equality, and closures. Mid-level rounds add performance patterns and async depth. Senior rounds test how you reason about trade-offs, architecture, and edge cases under load.

Tier Typical experience Question focus Example topic What interviewers probe
Junior 0-2 years Core language mechanics var vs let, data types, == vs === Whether the basics are solid
Mid 2-5 years Performance and async patterns Debouncing, throttling, memoization, promises Whether you write efficient, maintainable code
Senior 5+ years System reasoning and edge cases Event loop ordering, the modern standard library, scaling Whether you can defend trade-offs out loud

The 40 questions above span all three tiers, so use this map to see which level each one targets and the level a JavaScript mentor can help you reach. Most candidates over-prepare the tier they already find comfortable and under-prepare the one above it.

The junior who knows closures cold still stumbles on the mid-level question about how memoization actually caches a result, and that is the gap worth closing first. The tier you are interviewing for sets the standard your answers are measured against, so practice one level up from where you feel safe.

The ES2025 JavaScript questions most lists still miss

ES2025 questions cover modern syntax that older question banks never added, and most prep lists still leave them out. Interviewers reach for these because they reveal whether you have kept up with the language or stopped learning it three versions ago. The four clusters below map the questions worth rehearsing, and the modern syntax a JavaScript tutor drills before a senior loop.

Optional chaining and nullish coalescing test whether you write defensively

Optional chaining questions evaluate whether you read nested values defensively. The interviewer asks how you would safely read a nested value like user?.profile?.email without throwing a runtime error when something in the chain is missing.

The follow-up almost always covers nullish coalescing and when ?? behaves differently from ||. The honest answer is that || treats 0, "", and false as fallback triggers, while ?? only falls back on null or undefined, which is exactly the bug interviewers want you to catch.

Logical assignment operators extend the same idea. Expect a question on what a ??= b does versus a ||= b and a &&= b, because the difference between assigning only when a value is nullish and assigning when it is merely falsy is the kind of precision that separates a defensive coder from a careless one. The operator looks like syntactic sugar, but the interviewer is checking whether you know which falsy values it skips.

Set algebra and immutable array methods test whether you keep up with the language

Set algebra questions show whether you keep up with the language. The interviewer asks how the native Set.prototype.union, intersection, and difference methods replace the manual filter-and-loop code developers used to write by hand. The interviewer wants to see whether you reach for the modern method or reinvent it, and whether you know these operate on collections of unique values.

Immutable array methods come up the same way. A common question asks how toSorted differs from sort: toSorted returns a new array and leaves the original untouched, while sort mutates in place. The same contrast applies to toReversed and with, because each method returns a new array rather than mutating the original values.

Expect a related question on Object.groupBy and Map.groupBy, which group an array's values into buckets by a key function and replace a reduce that everyone used to copy from the same blog post. The pattern across all of these is immutability, and naming that pattern out loud is what earns the point.

Structured cloning and AbortController test whether you know the modern standard library

Structured cloning questions show whether you know the modern standard library. The interviewer asks whether you still reach for JSON.parse(JSON.stringify(...)) to deep-copy an object, and what that workaround quietly loses. The expected answer names structuredClone, which preserves Date objects, Map, Set, and circular references that the JSON round-trip silently drops or corrupts.

AbortController questions test whether you can cancel an in-flight asynchronous operation cleanly. The scenario is usually a fetch that needs to stop when a user navigates away or types a new search query, and the answer is passing an AbortController signal rather than letting stale requests resolve and overwrite fresh data. Both questions reward the candidate who knows the platform now ships a built-in tool where the old answer was a hack.

Private class fields and BigInt test the edges interviewers use to separate seniors

Private class fields questions evaluate the edges that separate senior candidates. The interviewer asks how the # prefix enforces true encapsulation, where older conventions like a leading underscore only signaled intent without enforcing it. The probe is whether you know that a #private field is inaccessible outside the class at the language level, not just by agreement.

BigInt questions ask when the Number primitive loses precision and why a value like 9007199254740993n needs a different type. The answer is that Number is a 64-bit float and safe only up to Number.MAX_SAFE_INTEGER, so any integer past that point needs BigInt to stay exact. It is a small edge, but it is the kind of edge senior interviewers use to find out whether you understand how JavaScript represents numbers under the hood.

Scenario and debugging questions interviewers now favor

Scenario questions test reasoning rather than recall. They hand you a snippet and ask what it logs and why. The classic is a for loop using var with a setTimeout inside it that prints the final value three times instead of 0, 1, 2.

Interviewers favor this format because the right answer requires you to explain a mechanism, not name a definition.

Here is why that snippet behaves the way it does. Because var is function-scoped, every callback closes over the same single variable, and by the time the timers fire the loop has finished and that shared variable holds its final value. Switching to let fixes it, since let is block-scoped and gives each iteration its own binding.

The reasoning ties together scope, closures, and asynchronous timing in one answer, which is precisely why interviewers like it.

A related scenario asks for the log order of a setTimeout, a resolved Promise, and a synchronous line. The order is fixed, and it comes out like this:

  1. The synchronous line runs first, because synchronous code always finishes before any queued callback.
  2. The resolved promise's callback runs next, because microtasks drain before the next macrotask.
  3. The setTimeout callback runs last, because timers sit on the macrotask queue.

Getting this right means you understand the event loop's microtask and macrotask queues, not just that "promises are async." A strong candidate names the queue, walks the order, and explains the why in one breath.

What makes these questions hard to self-assess is that you can be confidently wrong. You read the explanation, nod, and still trip on the live follow-up, because reading the value of a snippet on the page never forces you to commit to an answer. Scenario answers are easy to get wrong silently, which is why saying your reasoning out loud to someone who can push back is the only way to find the gaps before the interviewer does.

A four-week approach to prepare for a JavaScript interview

Start a four-week JavaScript interview prep plan by locking down fundamentals first, then layering modern syntax, scenario practice, and live rehearsal on top. The sequence matters: rehearsing answers before the underlying concepts are solid just rehearses your gaps. Treat each week as a checkpoint, not a deadline.

  1. Week 1: Lock down the fundamentals - scope, closures, this binding, the var vs let distinction, and the event loop. These are table stakes, and a shaky answer here ends a junior round fast.
  2. Week 2: Add the ES2025 cluster - optional chaining, nullish coalescing, Set algebra, and the immutable array methods like toSorted. Write small examples for each so the syntax becomes muscle memory rather than trivia.
  3. Week 3: Work scenario and debugging questions out loud, explaining each answer as you go. Cover the classic setTimeout loop and the event-loop ordering puzzle, and narrate the reasoning, not just the result.
  4. Week 4: Run timed mock interviews with a mentor and get feedback on your actual answers, not just whether they were right. Candidates who prepare with others feel significantly more prepared than those who practice alone (FSE, 2025), so this is the week that converts knowledge into delivery. Book mock interview coaching to rehearse under realistic pressure.

The plan compresses or stretches with your timeline, but the order holds: concepts, then modern syntax, then reasoning, then live reps. The mentor in week four is not a luxury bolt-on; it is the only step that tests whether the first three weeks actually stuck. If you have one week instead of four, run the same sequence at speed and spend the most time on the rehearsal, because that is where most candidates are weakest.

Why a question list alone won't get you the offer

A question list alone won't get you the offer because it tells you what good answers look like without telling you whether you can produce one when a stranger is evaluating you. The 40 cards above are a strong reference. They still cannot put you in the chair and ask a follow-up you did not anticipate.

The evidence backs the limitation. Candidates who prepare with others feel significantly more prepared than those who study alone, because a second person catches errors, pools knowledge you do not have, and reduces the memory load of rehearsing everything solo (FSE, 2025).

That is perceived readiness, not a guaranteed pass, but feeling under-prepared walking into a live round is its own failure mode. Explaining an asynchronous answer out loud surfaces the gaps that silently reading a snippet never will.

The value of practicing with someone is only as good as that someone. A junior peer can run a mock interview, but they cannot tell you that your event-loop explanation is technically correct yet would lose a senior interviewer at "the microtask queue." A vetted bar is what makes the difference: under 5% of mentor applicants are accepted, which separates practicing against an interviewer's standard from practicing against a friend's encouragement.

The honest concession is that this page's own cards are only half the job, and you can get the other half through technical interview coaching with someone who has graded the real thing.

How mentor practice closes the preparation gap

Mentor practice closes the preparation gap by reproducing the live conditions solo study cannot: pooled knowledge, real-time error correction, and observational learning, the exact mechanisms the research points to (FSE, 2025). A static list cannot interrupt you mid-answer to say you buried the point, and that interruption is where most of the learning happens.

The mechanism is concrete. A mentor runs a timed mock interview, then reviews your actual answers over async chat between sessions, so the feedback covers both how you reasoned live and how you would tighten it next time. Mentees rate the experience 4.9 out of 5 across more than 20,000 reviews, repeatedly citing the personalized feedback that a question bank by design cannot give. That sentiment is the part of mentor value a static page can describe but never deliver.

Matching matters as much as the method. With 6,700+ vetted mentors, you can rehearse with a frontend engineer who actually interviews candidates at your target company or works in your target stack, which means the practice questions resemble the ones you will face. The breadth is what lets the practice land on your specific gap rather than a generic one, and a platform featured by Forbes, Inc., and Entrepreneur sits behind that match.

The outcomes follow. Michele, a MentorCruise mentee from a small university in southern Italy, landed a Tesla internship after his mentor Davide Pollicino helped him close gaps in algorithms and system design, refine his resume, and prepare through mock interviews (read Michele's full story). His preparation was not reading a longer list; it was rehearsing the answers with someone who knew what the bar looked like.

You can set up the same kind of practice through JavaScript coaching with a mentor matched to your goal, starting with a free first call before you commit to anything.

Frequently asked questions

How do I prepare for a JavaScript interview?

Start with the fundamentals, add ES2025 syntax, then rehearse scenario questions out loud through timed mock interviews. Lock down scope, closures, and the event loop first, layer on modern syntax like optional chaining and immutable array methods, and finish by practicing your delivery with someone who can push back on your reasoning. Reading answers builds knowledge; rehearsing them builds readiness.

What JavaScript topics should I study for an interview?

Cover closures, the event loop, this binding, == vs ===, prototypal inheritance, and the ES2025 additions most lists skip. The fundamentals show up in every junior round, while mid-level rounds add performance patterns like debouncing, throttling, and memoization. Senior rounds probe the modern standard library and how you reason about trade-offs, so spread your study across all three tiers.

Why does a for loop with var and setTimeout print the same number?

Function scope is the reason. Every callback closes over the same single function-scoped var variable, so they all read its final value. By the time the timers fire, the loop has finished and that shared variable holds its last value. Switching var to let fixes it, since let is block-scoped and gives each iteration its own binding.

Are JavaScript question lists enough to prepare, or do I need to practice?

It depends on your goal. Lists teach what good answers look like; practice teaches whether you can deliver them under pressure. A question bank is a strong reference for the "what," yet it cannot tell you if you will freeze on a live follow-up. Candidates who prepare with others feel significantly more prepared than those who go it alone (FSE, 2025), so pairing a list with rehearsal closes the gap reading cannot.

Still not convinced? Don't just take our word for it

We've already delivered 1-on-1 mentorship to thousands of students, professionals, managers and executives. Even better, they've left an average rating of 4.9 out of 5 for our mentors.

Find JavaScript Interview Coaches